标签:dig 个数 -- 查询 cas struct stdout fine for
将树分为若干条重链和轻链 ,再用线段树维护
模板https://www.luogu.org/problemnew/show/P3384
#include<bits/stdc++.h> using namespace std; #define ll long long void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);} void FCL(){fclose(stdin);fclose(stdout);} inline ll rd() { ll x=0,ert=1;char lk=getchar(); while(!isdigit(lk)){if(lk==‘-‘) ert=-1;lk=getchar();} while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-‘0‘);lk=getchar();} return x*ert; } const int N=1e5+10; struct zx{int nx,to;}e[N<<1]; struct zy{int l,r,len,sum,fl;}s[N<<2]; int h[N],nm,sz[N],son[N],fa[N],seg[N],a[N],A[N],dep[N],top[N],P,cnt; void ud(int p,int x) {s[p].sum+=((ll)s[p].len*(ll)x);s[p].fl+=x;s[p].sum%=P;s[p].fl%=P;} void df(int x) { dep[x]=dep[fa[x]]+(sz[x]=1); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==fa[x]) continue; fa[y]=x;df(y);sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } void dfs(int x) { a[seg[x]=++cnt]=A[x]; if(!son[x]) return ; top[son[x]]=top[x];dfs(son[x]); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==fa[x]||y==son[x]) continue; top[y]=y;dfs(y); } } void biu(int p,int l,int r) { s[p].l=l;s[p].r=r; if(l==r) {s[p].sum=a[l];s[p].len=1;return ;} biu(p<<1,l,(l+r)>>1);biu(p<<1|1,((l+r)>>1)+1,r); s[p].len=s[p<<1].len+s[p<<1|1].len; s[p].sum=s[p<<1].sum+s[p<<1|1].sum;s[p].sum%=P; } void add(int p,int l,int r,int x) { if(l<=s[p].l&&r>=s[p].r) {ud(p,x);return ;} if(s[p].fl) ud(p<<1,s[p].fl),ud(p<<1|1,s[p].fl),s[p].fl=0; int mid=(s[p].l+s[p].r)>>1; if(l<=mid) add(p<<1,l,r,x); if(r>mid) add(p<<1|1,l,r,x); s[p].sum=s[p<<1].sum+s[p<<1|1].sum,s[p].sum%=P; } int wy(int p,int l,int r) { if(l<=s[p].l&&r>=s[p].r)return s[p].sum; if(s[p].fl) ud(p<<1,s[p].fl),ud(p<<1|1,s[p].fl),s[p].fl=0; int mid=(s[p].l+s[p].r)>>1,ans=0; if(l<=mid) ans+=wy(p<<1,l,r); if(r>mid) ans+=wy(p<<1|1,l,r); s[p].sum=s[p<<1].sum+s[p<<1|1].sum,s[p].sum%=P; return ans%P; } int QA(int x,int y,int z) { int fx=top[x],fy=top[y],ans=0; while(fx!=fy) { if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy); if(z) add(1,seg[fx],seg[x],z); else ans+=wy(1,seg[fx],seg[x]),ans%=P; x=fa[fx];fx=top[x]; } if(dep[x]<dep[y]) swap(x,y); if(z) add(1,seg[y],seg[x],z); else ans+=wy(1,seg[y],seg[x]),ans%=P; return ans; } void Add(int x,int y){e[++nm].nx=h[x];h[x]=nm;e[nm].to=y;} int main() { int n=rd(),m=rd(),rt=rd();P=rd(); for(int i=1;i<=n;i++) A[i]=rd(); for(int i=1;i<n;i++) { int x=rd(),y=rd(); Add(x,y);Add(y,x); } df(rt);top[rt]=rt;dfs(rt);biu(1,1,n); for(int i=1;i<=m;i++) { int opt=rd(),x=rd(); switch(opt) { case 1:{int y=rd(),z=rd();QA(x,y,z);break;} case 2:{int y=rd();printf("%d\n",QA(x,y,0));break;} case 3:{int z=rd();add(1,seg[x],seg[x]+sz[x]-1,z);break;} case 4:{printf("%d\n",wy(1,seg[x],seg[x]+sz[x]-1));break;} } } return 0; }
题目大意:在一棵树上询问两个点之间的颜色段和修改一个节点的颜色。链接: https://loj.ac/problem/10141
思路:因为树链剖分查询时是从两个端点开始向上搜链,所以记录一下每次两条链连接的部分的颜色,相同就--;
线段树内记录左右儿子的左右端点的颜色,如果中间可合并为一段,就--;
#include<bits/stdc++.h> using namespace std; #define ll long long inline ll rd() { ll x=0,ert=1;char lk=getchar(); while(!isdigit(lk)){if(lk==‘-‘) ert=-1;lk=getchar();} while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-‘0‘);lk=getchar();} return x*ert; } const int N=1e5+10; struct zx{int nx,to;}e[N<<1]; struct zy{int l,r,sum,fl,lc,rc;}s[N<<2]; int dep[N],cnt,fa[N],sz[N],son[N],id[N],a[N],A[N],top[N],h[N],nm,L,R; void df(int x,int F) { dep[x]=dep[fa[x]=F]+(sz[x]=1); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==F) continue; df(y,x);sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } void dfs(int x,int F) { a[id[x]=++cnt]=A[x]; if(!son[x]) return ; top[son[x]]=top[x];dfs(son[x],x); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==F||y==son[x]) continue; dfs(top[y]=y,x); } } void zw(int p,int c){s[p].lc=c,s[p].rc=c,s[p].sum=1;s[p].fl=c;} void up(int p) { s[p].sum=s[p<<1].sum+s[p<<1|1].sum; s[p].lc=s[p<<1].lc;s[p].rc=s[p<<1|1].rc; if(s[p<<1].rc==s[p<<1|1].lc) s[p].sum--; } void biu(int p,int l,int r) { s[p].l=l;s[p].r=r; if(l==r) {zw(p,a[l]);s[p].fl=0;return ;} biu(p<<1,l,(l+r)>>1);biu(p<<1|1,((l+r)>>1)+1,r); up(p); } void ud(int p){zw(p<<1,s[p].fl),zw(p<<1|1,s[p].fl),s[p].fl=0;} void add(int p,int l,int r,int c) { if(l<=s[p].l&&r>=s[p].r){zw(p,c);return ;} if(s[p].fl) ud(p); int mid=(s[p].l+s[p].r)>>1; if(l<=mid) add(p<<1,l,r,c); if(r>mid) add(p<<1|1,l,r,c); up(p); } int wy(int p,int l,int r) { if(l<=s[p].l&&r>=s[p].r) {if(!L) L=s[p].lc;R=s[p].rc;return s[p].sum;} if(s[p].fl) ud(p); int mid=(s[p].l+s[p].r)>>1,x=0,y=0; if(l<=mid) x=wy(p<<1,l,r); if(r>mid) y=wy(p<<1|1,l,r); if(x&&y&&s[p<<1].rc==s[p<<1|1].lc) x--; up(p); return x+y; } int QA(int x,int y,int z) { int ans=0,l[2]={0},fl=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y),fl^=1; if(z) add(1,id[top[x]],id[x],z); if(!z) {L=0;R=0;ans+=wy(1,id[top[x]],id[x]);if(l[fl]==R) ans--;l[fl]=L;} x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y),fl^=1; if(z) add(1,id[x],id[y],z); if(!z) {L=R=0;ans+=wy(1,id[x],id[y]);if(l[fl]==L) ans--;if(l[fl^1]==R) ans--;} return ans; } void Add(int x,int y){e[++nm].nx=h[x];e[nm].to=y;h[x]=nm;} int main() { int n=rd(),m=rd(),x,y,w;char c; for(int i=1;i<=n;i++) A[i]=rd(); for(int i=1;i<n;i++) x=rd(),y=rd(),Add(x,y),Add(y,x); df(1,0);dfs(1,0);biu(1,1,n); for(int i=1;i<=m;i++) { cin>>c; x=rd(),y=rd(); if(c==‘C‘) w=rd(),QA(x,y,w); else printf("%d\n",QA(x,y,0)); } return 0; }
题目大意:一棵树上每个节点有两个状态0/1,给出一个点 求此点到根节点的链上状态为1的节点数输出,并将这些节点状态赋0;或求以此节点为根节点的子数状态为0的个数输出,并将这些节点的状态赋1;
思路:一个区间内就两种状态,维护一下;
#include<bits/stdc++.h> using namespace std; #define ll long long void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);} void FCL(){fclose(stdin);fclose(stdout);} inline ll rd() { ll x=0,ert=1;char lk=getchar(); while(!isdigit(lk)){if(lk==‘-‘) ert=-1;lk=getchar();} while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-‘0‘);lk=getchar();} return x*ert; } const int N=1e5+10; struct zx{int nx,to;}e[N]; struct zy{int l,r,sum,fl;}s[N<<2]; int top[N],dep[N],cnt,son[N],fa[N],id[N],nm,h[N],sz[N]; void df(int x) { dep[x]=dep[fa[x]]+(sz[x]=1); for(int i=h[x],y;i;i=e[i].nx) { df(y=e[i].to);sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } void dfs(int x) { id[x]=++cnt; if(!son[x]) return ; top[son[x]]=top[x];dfs(son[x]); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==son[x]) continue; top[y]=y;dfs(y); } } void biu(int p,int l,int r) { s[p].l=l;s[p].r=r;s[p].fl=-1;s[p].sum=r-l+1; if(l==r) return ; biu(p<<1,l,(l+r)>>1);biu(p<<1|1,((l+r)>>1)+1,r); } void ud(int p,int x){s[p].sum=(s[p].r-s[p].l+1)*x;s[p].fl=x;} int add(int p,int l,int r,int x,int y) { if(l<=s[p].l&&r>=s[p].r) { int q=s[p].sum*x+(s[p].r-s[p].l+1-s[p].sum)*y;ud(p,y); return q; } if(s[p].fl>=0) ud(p<<1,s[p].fl),ud(p<<1|1,s[p].fl),s[p].fl=-1; int mid=(s[p].l+s[p].r)>>1,q=0; if(l<=mid) q+=add(p<<1,l,r,x,y); if(r>mid) q+=add(p<<1|1,l,r,x,y); s[p].sum=s[p<<1].sum+s[p<<1|1].sum; return q; } int AQ(int x) { int ans=0; while(x) { ans+=add(1,id[top[x]],id[x],1,0); x=fa[top[x]]; } return ans; } void add(int x,int y){e[++nm].to=y;e[nm].nx=h[x];h[x]=nm;fa[y]=x;} int main() { int n=rd(); for(int i=1;i<n;i++) add(rd()+1,i+1); df(1);dfs(1);biu(1,1,n); int m=rd(); char c[50]; for(int i=1;i<=m;i++) { scanf("%s",c+1);int x=rd()+1; if(c[1]==‘i‘) printf("%d\n",AQ(x)); else printf("%d\n",add(1,id[x],id[x]+sz[x]-1,0,1)); } return 0; }
题目大意:给定一棵树,给每个节点一个种类,一个值,共n个节点,c种 种类,(1<=n,c<=1e5);
1:求两个节点之间(两个节点同类)与这两个节点同类的值和;
2:求两个节点之间(两个节点同类)与这两个节点同类的最大值;
3:修改某个节点的种类;
4:修改某个节点的值;
思路:建c颗线段树动态开点
#include<bits/stdc++.h> using namespace std; #define ll long long void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);} void FCL(){fclose(stdin);fclose(stdout);} inline ll rd() { ll x=0,ert=1;char lk=getchar(); while(!isdigit(lk)){if(lk==‘-‘) ert=-1;lk=getchar();} while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-‘0‘);lk=getchar();} return x*ert; } const int N=1e5+10; struct zx{int nx,to;}e[N<<1]; int w[N],c[N],nm,n,h[N]; int ls[N<<4],rs[N<<4],sum[N<<4],mx[N<<4],rt[N],cnt; int dep[N],fa[N],top[N],son[N],sz[N],id[N],cn; void df(int x,int F) { dep[x]=dep[fa[x]=F]+(sz[x]=1); for(int i=h[x],y;i;i=e[i].nx) { if((y=e[i].to)==F) continue; df(y,x);sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } void dfs(int x) { id[x]=++cn; if(!son[x]) return ; top[son[x]]=top[x];dfs(son[x]); for(int i=h[x],y;i;i=e[i].nx) if(!(dep[y=e[i].to]<dep[x]||y==son[x])) dfs(top[y]=y); } void up(int p){sum[p]=sum[ls[p]]+sum[rs[p]];mx[p]=max(mx[ls[p]],mx[rs[p]]);} void cag(int &p,int l,int r,int su,int x) { if(!p) p=++cnt; if(l==r){sum[p]=mx[p]=su;return ;} int mid=(l+r)>>1; if(x<=mid) cag(ls[p],l,(l+r)>>1,su,x); if(x>mid) cag(rs[p],((l+r)>>1)+1,r,su,x); up(p); } int askmx(int p,int l,int r,int x,int y) { if(!p) return 0; if(x<=l&&y>=r) return mx[p]; int mid=(l+r)>>1,ans=0; if(x<=mid) ans=askmx(ls[p],l,mid,x,y); if(y>mid) ans=max(ans,askmx(rs[p],mid+1,r,x,y)); return ans; } int asksum(int p,int l,int r,int x,int y) { if(!p) return 0; if(x<=l&&y>=r) return sum[p]; int mid=(l+r)>>1,ans=0; if(x<=mid) ans=asksum(ls[p],l,mid,x,y); if(y>mid) ans+=asksum(rs[p],mid+1,r,x,y); return ans; } int QA(int x,int y,bool fl) { int P=rt[c[x]],ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); if(fl) ans+=asksum(P,1,n,id[top[x]],id[x]); if(!fl) ans=max(ans,askmx(P,1,n,id[top[x]],id[x])); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); if(fl) ans+=asksum(P,1,n,id[x],id[y]); if(!fl) ans=max(ans,askmx(P,1,n,id[x],id[y])); return ans; } void add(int x,int y){e[++nm].nx=h[x];h[x]=nm;e[nm].to=y;} int main() { n=rd();int Q=rd(),x,y;char p[5]; for(int i=1;i<=n;i++) w[i]=rd(),c[i]=rd(); for(int i=1;i<n;i++){x=rd(),y=rd();add(x,y);add(y,x);} df(1,0);dfs(1); for(int i=1;i<=n;i++) cag(rt[c[i]],1,n,w[i],id[i]); for(int i=1;i<=Q;i++) { scanf("%s",p);x=rd(),y=rd(); if(p[0]==‘C‘) { if(p[1]==‘C‘) cag(rt[c[x]],1,n,0,id[x]),c[x]=y,cag(rt[c[x]],1,n,w[x],id[x]); if(p[1]==‘W‘) cag(rt[c[x]],1,n,y,id[x]),w[x]=y; } if(p[0]==‘Q‘) { if(p[1]==‘S‘) printf("%d\n",QA(x,y,1)); if(p[1]==‘M‘) printf("%d\n",QA(x,y,0)); } } return 0; }
标签:dig 个数 -- 查询 cas struct stdout fine for
原文地址:https://www.cnblogs.com/LWL--Figthing/p/9756460.html