zoukankan      html  css  js  c++  java
  • **浅谈差分【复习】**

    https://www.luogu.org/problem/P5026

    分析:

    区间加上一个等差序列,两次差分完成

    code :

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,m;
    int aa[2100000],bb[2100000];
    #define isdigit(x) ((x)>='0'&&(x)<='9')
    inline int read(){
        int a=0,flag=1;
        char c=getchar();
        while(!isdigit(c)){
            if(c=='-')flag=-1;
            c=getchar();
        }
        while(isdigit(c)){
            a=(a<<1)+(a<<3)+c-48;
            c=getchar();
        }
        return a*flag;
    }
    int main(){
        n=read(),m=read();
        int *a=aa+1000000,*b=bb+1000000;
        for(int i=1;i<=n;++i){
            int v=read(),x=read();
            a[x-3*v+1]++;
            a[x-2*v+1]-=2;
            a[x+1]+=2;
            a[x+2*v+1]-=2;
            a[x+3*v+1]++;
        }
        for(int i=-40000;i<=m+40000;++i)a[i]+=a[i-1],b[i]+=b[i-1]+a[i];
        for(int i=1;i<=m;++i)printf("%d ",b[i]);
        return 0;
    }
    

    https://www.luogu.org/problem/P4623

    分析:

    对x轴和y轴分别维护一个树状数组,

    支持区间加和单点查询,用差分

    code by wzxbeliever:

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define ri register int
    #define lowbit(x) x&(-x)
    using namespace std;
    const int maxn=1e5+5;
    const int maxx=1e6+5;
    int n,m,a,b,c,d,e,f,val;
    int X[maxx],Y[maxx];
    char ch1,ch2;
    il void add(int x,int p){while(x<=maxx)X[x]+=p,x+=lowbit(x);}
    il int query(int x){int res=0;while(x)res+=X[x],x-=lowbit(x);return res;}
    il void add2(int x,int p){while(x<=maxx)Y[x]+=p,x+=lowbit(x);}
    il int query2(int x){int res=0;while(x)res+=Y[x],x-=lowbit(x);return res;}
    int main(){
    	scanf("%d",&n);
    	for(ri i=1;i<=n;i++){
    	int Lmin,Rmin,Lmax,Rmax;
    	Lmax=Rmax=0;Lmin=Rmin=maxx; 
    	scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);
    	a++,b++,c++,d++,e++,f++;
    	Lmin=min(a,min(c,e));
    	Rmin=min(b,min(d,f));
    	Lmax=max(a,max(c,e));
    	Rmax=max(b,max(d,f));
    	Lmin++;Rmin++;
    	add(Lmin,1);add(Lmax,-1);
    	add2(Rmin,1);add2(Rmax,-1);	
    	}
    	scanf("%d",&m);
    	while(m--){
    		cin>>ch1>>ch2>>val;val++;
    		if(ch1=='x')printf("%d
    ",query(val));
    		else printf("%d
    ",query2(val));
    	}
    	return 0;
    }
    
    

    https://www.luogu.org/problem/P2680

    分析:

    很早就做过了,现在发现又不会了

    模仿一下考试过程:

    一棵树,m个计划,可将一条边权附为0 ,最大值最小

    典型的二分答案:

    关键在于check()函数怎么写

    考虑此时小于mid的路径都不会产生影响了

    大于mid的所有边中,如果存在一条公共边,它的边权为k

    使得减掉k之后所有边都小于等于mid

    则return true 否则 return false

    剩下就是统计出这条公共边了

    用树上差分统计

    总的来说就是

    LCA+树上差分+二分

    code by std:

    #include<bits/stdc++.h>
    #define IL inline
    #define RI register int
    #define N  300008
    using namespace std;
    IL void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();}
    	while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    struct node{
    	int x , y , lca , dis ; 
    	bool operator < (const node & a ) const {
    		return dis < a.dis ; 
    	}
    }query[N];
    int depth[N],f[N][21],Dis[N],n,head[N],tot,k,ans,init[N],cnt[N];
    struct cod{int u,v,w;}edge[N<<1];
    int l,r,m;
    IL void add(int x,int y,int z)
    {
    	edge[++tot].u=head[x];
    	edge[tot].v=y;
    	edge[tot].w=z;
    	head[x]=tot;
    }
    void dfs(int u,int fa , int dis)
    {
    	depth[u]=depth[fa]+1;
    	f[u][0]=fa ; init[u] = dis;
     	for(RI i=1;(1<<i)<=depth[u];i++)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(RI i=head[u];i;i=edge[i].u)
    	{
    		if(edge[i].v==fa)continue;
    		Dis[edge[i].v]=Dis[u]+edge[i].w;
    		dfs(edge[i].v,u,edge[i].w);
    	}
    }
    IL int lca(int x,int y)
    {
    	if(depth[x]>depth[y])swap(x,y);
    	for(RI i=20;i>=0;i--)
    		if(depth[y]-(1<<i)>=depth[x])
    			y=f[y][i];
    	if(x==y)return x;
    	for(RI i=20;i>=0;i--)
    	{
    		if(f[x][i]==f[y][i])continue;
    		x=f[x][i],y=f[y][i];
    	}
    	return f[x][0];
    }
    void dfss(int u,int fa)
    {
    	for(RI i=head[u];i;i=edge[i].u)
    	{
    		if(edge[i].v==fa)continue;
    		dfss(edge[i].v,u);
    		cnt[u]+=cnt[edge[i].v];
    	}
    }
    IL bool ok(int x)
    {
    	int num=0,now=0;
    	for(RI i=1;i<=n;i++)cnt[i]=0;
    	for(RI i=1;i<=m;i++)
    	{
    		if(query[i].dis<=x)continue;
    		cnt[query[i].x]++;cnt[query[i].y]++;
    		cnt[query[i].lca]-=2;
    		num++;
    	}
    	dfss(1,0);
    	for(RI i=1;i<=n;i++)
    	{
    		if(cnt[i]==num)now=max(now,init[i]);
    	}
    	return query[m].dis-now<=x;
    }
    int main()
    {
    	in(n),in(m);
    	for(RI i=1,x,y,z;i<n;i++)
    	{
    		in(x),in(y),in(z);
    		add(x,y,z);add(y,x,z);
    	}
    	dfs(1,0,0);	
    	for(RI i=1,x,y;i<=m;i++)
    	{
    		in(x),in(y);
    		query[i].lca=lca(x,y);
    		r=max(r,(query[i].dis=Dis[x]+Dis[y]-2*Dis[query[i].lca]));
    		query[i].x = x,query[i].y = y;
    	}
    	sort(query+1,query+m+1);
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(ok(mid))r=mid-1;
    		else l=mid+1;
    	}
    	printf("%d",l);
    }
    

    盗取衡水的一道题:居然和jklover以前出的题一样

    题目描述

    科学家在“无限神机”(Infinity MachineInfinity Machine)找到一个奇怪的机制,这个机制有NN个元件,有MM条电线连接这些元件,所有元件都是连通的。两个元件之间可能有多条电线连接。
    科学家对这些元件可以任意地设置为“高电压”和“低电压”两种模式,如果一条电线的一端为高电压,另一端为低电压,这条电线就会产生电流。
    为了安全的研究“无限神机”,科学家需要找到一条电线,将它的两端设为相同的电压,并且除选择的这条电线外,其它所有电线都有电流(否则就没有研究的价值了)。
    有多少条电线满足这样的条件?

    分析:

    像这种只有两个对立面的,一般和二分图,奇环,偶环有关

    首先偶环上的边肯定没法删,也可以说是不用删

    再考虑奇环,首先一个奇环一定是要删一条边的,

    但是如果有多个奇环,但是你又只能删一条边怎么办?

    那这条边就必须被所有奇环都覆盖,并且不能再偶环上

    边覆盖问题差分维护 边差分

    还要注意的是这里差分没有用到LCA

    因为此时lca(a,b)==a||b

    还有就是这个代码里的in数组很是巧妙

    code:

    #include<bits/stdc++.h>
    using namespace std;
    struct rec{int nxt,to;bool dead;}e[400002];
    int head[100001],cnt=1;
    int n,m;
    int odd[100001],eve[100001],cut[400002],depth[100001],in[100001];
    bool vis[100001];
    int ans;
    void add(int x,int y)
    {
        e[++cnt].nxt=head[x];
        e[cnt].to=y;
        head[x]=cnt;
    }
    void dfs(int x)
    {
        vis[x]=1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(cut[i])continue;
            cut[i]=cut[i^1]=1;
            if(vis[e[i].to])
            {
                if((depth[x]-depth[e[i].to])&1){eve[e[i].to]--;eve[x]++;}
                else{odd[e[i].to]--;odd[x]++;odd[0]++;}
            }
            else
            {
                depth[e[i].to]=depth[x]+1;
                in[e[i].to]=i;
                dfs(e[i].to);
            }
        }
    }
    void dfs(int x,int f)
    {
        for(int i=head[x];i;i=e[i].nxt)
            if(in[e[i].to]==i)
            {
                dfs(e[i].to,x);
                odd[x]+=odd[e[i].to];
                eve[x]+=eve[e[i].to];
            }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
        if(odd[0]==1)ans=1;
        for(int i=1;i<=n;i++)if(!in[i])dfs(i,0);
        for(int i=1;i<=n;i++)
            if(in[i]&&odd[i]==odd[0]&&!eve[i])ans++;
        printf("%d",ans);
        return 0;
    }
    

    分析:

    考虑维护差分数组

    对于区间加[L,R],发现区间里的数的贡献不会变动,只有L-1,L+1,R+1,R

    这四个位置的数的贡献可能会变

    所以特判一下,利用树状数组维护前缀和

    code by std:

    #include <cstdio>
    #define maxn 200005
    #define lowbit(x) (x&(-(x)))
    #define LL long long
    LL a[maxn];
    int n,m;
    struct TreeArr{
        int a[maxn];
        void add(int x,int v){
            while(x<=n){
                a[x]+=v;
                x+=lowbit(x);
            }
        }
        int query(int pos){
            int ret=0;
            while(pos){
                ret+=a[pos];
                pos^=lowbit(pos);
            }
            return ret;
        }
    } tree;
    bool check(int x){
        return (a[x]<0&&a[x+1]>0)||(a[x]>0&&a[x+1]<0);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=n;i>=1;i--){
            a[i]-=a[i-1];
            if(a[i]*a[i+1]<0)tree.add(i,1);
        }
        for(int i=1;i<=m;i++){
            int op;scanf("%d",&op);
            if(op){
                int x,y,z;scanf("%d%d%d",&x,&y,&z);
                int px=check(x),py=check(y);
                int px1=check(x-1),py1=check(y+1);
                a[x]+=z;a[y+1]-=z;
                int nx=check(x),ny=check(y);
                int nx1=check(x-1),ny1=check(y+1);
                tree.add(x,nx-px);
                if(x>1)tree.add(x-1,nx1-px1);
                if(x!=y)tree.add(y,ny-py);
                tree.add(y+1,ny1-py1);
            }
            else {
                int x,y;scanf("%d%d",&x,&y);
                if(x==y)printf("0
    ");
                else printf("%d
    ",tree.query(y-1)-tree.query(x));
            }
        }
    }
    
  • 相关阅读:
    手机管理中的应用【6】——电源管理篇
    NYOJ 14 场地安排(它可以被视为一个经典问题)
    YUV格式转换RGB(基于opencv)
    互联网金融进入洗礼阶段,控制风险是制胜之道
    Uva 409-Excuses, Excuses!(串)
    MATLAB新手教程
    IE无法打开internet网站已终止操作的解决的方法
    关于SetCapture() 和 ReleaseCapture()的使用方法
    wxWidgets刚開始学习的人导引(2)——下载、安装wxWidgets
    MyReport报表引擎2.7.6.7新功能
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11853252.html
Copyright © 2011-2022 走看看