• csp-s模拟测试56Merchant, Equation,Rectangle题解


    题面:https://www.cnblogs.com/Juve/articles/11619002.html

    merchant:

    二分答案,贪心选前m大的

    但是用sort复杂度不优,会T掉

    我们只是找前m大的,至于前m大的如何排序我们并不关心

    所以用nth_element()函数找出前m大的,然后贪心check

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    #define re register
    using namespace std;
    const int MAXN=1e6+5;
    int n,m,s,l=0,r=1e9,mid,d[MAXN];
    struct node{
    	int k,b;
    }c[MAXN];
    int max(int a,int b){
    	return a>b?a:b;
    }
    inline bool check(re int x){
    	re int res=0;
    	for(int i=1;i<=n;++i) d[i]=c[i].k*x+c[i].b;
    	nth_element(d+1,d+n-m+1,d+n+1);
    	for(re int i=n-m+1;i<=n;++i){
    		res+=max(0,d[i]);
    		if(res>=s) return 1;
    	}
    	return res>=s;
    }
    signed main(){
    	scanf("%lld%lld%lld",&n,&m,&s);
    	for(re int i=1;i<=n;++i) scanf("%lld%lld",&c[i].k,&c[i].b);
    	while(l<r){
    		mid=(l+r)>>1;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%lld
    ",l);
    	return 0;
    }
    

    equation:

    我们化减一下就能得出每个$x_i$关于$x_1$的关系:

    若设$deep[1]=1$,则:${x_1}pm{x_i}=t_i$,每个节点i都能表示成这个式子,

    $deep[x_i]$是偶数就是加,奇数就是减

    把边权放到点权,那么:

    $t_i=sum k*w[j]$,其中j是i到根节点路径上的点,$k=pm1$,$deep[x_i]$是偶数就是1,奇数就是-1,

    对于$t_i$,我们可以用树状数组查询,修改用差分思想,注意deep[i]的正负

    询问就是三个未知数三个方程

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    #define re register
    using namespace std;
    const int MAXN=1e6+5;
    int n,q,vall,fa[MAXN],w[MAXN];
    int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],cnt=0,val[MAXN<<1];
    void add(int u,int v,int ww){
    	++cnt,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt,val[cnt]=ww;
    }
    int c[MAXN];
    int lowbit(int x){
        return x&(-x);
    }
    void update(int pos,int val){
        for(int i=pos;i<=n;i+=lowbit(i)){
            c[i]+=val;
        }
    }
    int query(int pos){
        int res=0;
        for(int i=pos;i>0;i-=lowbit(i)){
            res+=c[i];
        }
        return res;
    }
    int deep[MAXN],dfn=0,rk[MAXN],id[MAXN],idd[MAXN];
    void dfs(int x,int f,int dep){
        deep[x]=dep;
        rk[++dfn]=x;
        id[x]=dfn;
        for(int i=pre[x];i;i=nxt[i]){
            int y=to[i];
            if(y==f) continue;
            dfs(y,x,dep+1);
        }
        idd[x]=dfn;
    }
    signed main(){
        //freopen("test.in","r",stdin);
    	scanf("%lld%lld",&n,&q);
    	if(q==0) return 0;
    	for(int i=2;i<=n;++i){
    		scanf("%lld%lld",&fa[i],&w[i]);
    		add(i,fa[i],w[i]),add(fa[i],i,w[i]);
    	}
        dfs(1,0,1);
        for(int i=1;i<=n;++i){
            if((deep[i]&1)==0) update(id[i],w[i]),update(idd[i]+1,-w[i]);
            else update(id[i],-w[i]),update(idd[i]+1,w[i]);
        }
    	while(q--){
    	    int opt;
            scanf("%lld",&opt);
            if(opt==1){
                int u,v,s;
                scanf("%lld%lld%lld",&u,&v,&s);
                int p=query(id[u]),q=query(id[v]);
                if((deep[u]&1)==0&&(deep[v]&1)==0){//x1+xu=p,x1+xv=q;
                    int t=p+q-s;
                    if(t&1==1) puts("none");
                    else printf("%lld
    ",t/2);
                }
                else if((deep[u]&1)==0&&(deep[v]&1)==1){//x1+xu=p,x1-xv=q;
                    int t=p-q;
                    if(t==s) puts("inf");
                    else puts("none");
                }
                else if((deep[u]&1)==1&&(deep[v]&1)==0){
                    int t=q-p;
                    if(t==s) puts("inf");
                    else puts("none");
                }
                else{//x1-xu=p,x1-xv=q;
                    int t=p+q+s;
                    if((t&1)==1) puts("none");
                    else printf("%lld
    ",t/2);
                }
            }else{
                int u,ww;
                scanf("%lld%lld",&u,&ww);
                if((deep[u]&1)==0){
                    update(id[u],ww-w[u]),update(idd[u]+1,w[u]-ww);
                }else{
                    update(id[u],w[u]-ww),update(idd[u]+1,ww-w[u]);
                }
                w[u]=ww;
            }
    	}
    	return 0;
    }
    

    rectangle:

    不会了,只有n4暴力

    先考虑横坐标互不相同的情况。枚举矩形的右边界R和左边界L,假设左边界上的点的坐
    标为(L, y 1 ),右边界上的点的坐标为(R, y 2 ),不妨设y 1 ≤ y 2 ,考虑怎么一次计算所有左边界
    为L右边界为R的矩形的面积和。
    由于这些矩形的面积可以表示为(R − L) × (y max − y min ),可以发现我们只需要知道在
    所有L ≤ x ≤ R的点中,满足y ≤ y 1 的不同的y有多少个,以及它们的和;相应地还有满
    足y ≥ y 2 的信息。枚举右边界后,从大到小地枚举左边界,在移动左边界时用树状数组维护
    信息即可。
    现在考虑一般情况,以相同的方式枚举左右边界,此时横坐标为L或R的点可能有很多,
    这些点的纵坐标会划分出若干个区间,此时再枚举上边界的纵坐标所在的区间,即可得到对
    应的可行的下边界的区间,仍然可以用树状数组维护和查询。
    复杂度为O(nm log m),其中m为坐标范围。树状数组常数非常优秀,因此可以快速通
    过。
    bonus: 找到一个复杂度为O(nm)的做法。

  • 相关阅读:
    面试
    无中生有
    数字称王-0-10000,
    数组排序
    uiview 阴影
    TTTAtibutedlabel again
    vim配置python编程环境及YouCompleteMe的安装教程
    centos7下vim8.1的编译安装教程
    centos7下误执行chmod -R 777 /后的权限修复方法
    如何用浏览器在线查看.ipynb文件
  • 原文地址:https://www.cnblogs.com/Juve/p/11619013.html
Copyright © 2020-2023  润新知