洛谷P2590 树的统计(https://www.luogu.org/problem/P2590)
啊调了6个小时,血的教训啊。。。在树链剖分后,由于树按照DFN序重新编号,如果要直接调用线段树操作,需要操作ID[X]而不能直接操作编号X
#include#include #include #include #include using namespace std; const int maxn=30030; int head[maxn],top[maxn],dep[maxn],fa[maxn],id[maxn],sz[maxn],son[maxn]; int n,m,cnt,num,flag ,p,q,t; int a[maxn],b[maxn]; string k; struct pp { int u; int nex; }e[maxn*2]; struct kk { int l,r; int sum,maxl; }s[maxn*4]; void add(int x,int y) { e[++cnt].u=y; e[cnt].nex=head[x]; head[x]=cnt; } void up(int rt) { s[rt].sum=s[rt<<1].sum+s[rt<<1|1].sum; s[rt].maxl=max(s[rt<<1].maxl,s[rt<<1|1].maxl); } void build(int rt,int l,int r) { s[rt].l=l; s[rt].r=r; s[rt].maxl=-maxn*4; s[rt].sum=0; if(l==r) { s[rt].sum=s[rt].maxl=a[l]; return; } int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); up(rt); } int qsum(int rt,int l,int r) { if(l<=s[rt].l&&r>=s[rt].r) return s[rt].sum; int ans=0; int mid=(s[rt].l+s[rt].r)>>1; if(l<=mid) ans+=qsum(rt<<1,l,r); if(r>mid) ans+=qsum(rt<<1|1,l,r); return ans; } int qmax(int rt,int l,int r) { if(l<=s[rt].l&&r>=s[rt].r) return s[rt].maxl; int ans=-maxn*100; int mid=(s[rt].l+s[rt].r)>>1; if(l<=mid) ans=max(ans,qmax(rt<<1,l,r)); if(r>mid) ans=max(ans,qmax(rt<<1|1,l,r)); return ans; } void modify(int rt,int x,int v) { if(s[rt].l==s[rt].r&&s[rt].r==x) { s[rt].sum=s[rt].maxl=v; return; } int mid=(s[rt].l+s[rt].r)>>1; if(x<=mid) modify(rt<<1,x,v); else modify(rt<<1|1,x,v); up(rt); } void dfs1(int x,int f,int deep) { fa[x]=f; dep[x]=deep; sz[x]=1; int ms=-1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==f) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if(sz[y]>ms) { ms=sz[y]; son[x]=y; } } } void dfs2(int x,int tt) { id[x]=++num; a[num]=b[x]; top[x]=tt; if(!son[x]) return; dfs2(son[x],tt); for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } int anssum(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=qsum(1,id[top[x]],id[x]); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ans+=qsum(1,id[y],id[x]); return ans; } int ansmax(int x,int y) { int ans=-maxn*100; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap (x,y); ans=max(ans,qmax(1,id[top[x]],id[x])); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ans=max(ans,qmax(1,id[y],id[x])); return ans; } int main() { scanf("%d",&n); for(int i=1;i<=(n-1);i++) { int aa,bb; scanf("%d%d",&aa,&bb); add(aa,bb);add(bb,aa); } for(int i=1;i<=n;i++) scanf("%d",&b[i]); dfs1(1,0,1); dfs2(1,1); build(1,1,n); scanf("%d",&t); while(t--) { cin>>k; scanf("%d%d",&p,&q); if(k=="CHANGE") modify(1,id[p],q); else if(k=="QMAX") printf("%d\n",ansmax(p,q)); else printf("%d\n",anssum(p,q)); } return 0; }
洛谷P3178 树上操作(https://www.luogu.org/problem/P3178)
这题莫名要用long long。。。看来是有全部点排成一条链的奇葩情况。。。
另外如果批量修改int 的话还可以用
#define int long long signed main() {}
省的一个个手改了
#include#include #include #include #include using namespace std; const int maxn=100010; long long n,m,cnt,flag,num,res,t,p,q; long long head[maxn],top[maxn],son[maxn],id[maxn],sz[maxn],fa[maxn],dep[maxn],a[maxn],b[maxn]; struct pp { long long l,r; long long sum, tag; }s[maxn*4]; struct yy { long long u; long long nex; }e[maxn*2]; void add(long long x,long long y) { e[++cnt].u=y; e[cnt].nex=head[x]; head[x]=cnt; } void up(long long rt) { s[rt].sum=s[rt<<1].sum+s[rt<<1|1].sum; } void down(long long rt) { if(s[rt].tag) { s[rt<<1].sum=(s[rt<<1].sum+s[rt].tag*(s[rt<<1].r-s[rt<<1].l+1)); s[rt<<1|1].sum=(s[rt<<1|1].sum+s[rt].tag*(s[rt<<1|1].r-s[rt<<1|1].l+1)); s[rt<<1].tag=(s[rt<<1].tag+s[rt].tag); s[rt<<1|1].tag=(s[rt<<1|1].tag+s[rt].tag); s[rt].tag=0; } } void build(long long rt,long long l,long long r) { s[rt].l=l; s[rt].r=r; if(l==r) { s[rt].sum=a[l]; return; } long long mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); up(rt); } void modify(long long rt,long long l,long long r,long long v) { if(l<=s[rt].l&&r>=s[rt].r) { s[rt].sum+=(long long)v*(s[rt].r-s[rt].l+1); s[rt].tag+=v; return; } long long mid=(s[rt].l+s[rt].r)>>1; down(rt); if(l<=mid) modify(rt<<1,l,r,v); if(r>mid) modify(rt<<1|1,l,r,v); up(rt); } long long querry(long long rt,long long l,long long r) { if(l<=s[rt].l&&r>=s[rt].r) { return s[rt].sum; } down(rt); long long ans=0; long long mid=(s[rt].r+s[rt].l)>>1; if(l<=mid) ans=(ans+querry(rt<<1,l,r)); if(r>mid) ans=(ans+querry(rt<<1|1,l,r)); return ans; } void dfs1(long long x,long long f,long long deep) { fa[x]=f; dep[x]=deep; sz[x]=1; long long ms=-1; for(long long i=head[x];i;i=e[i].nex) { long long y=e[i].u; if(y==f) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if(ms<sz[y]) { ms=sz[y]; son[x]=y; } } } void dfs2(long long x,long long tt) { id[x]=++num; a[num]=b[x]; top[x]=tt; if(!son[x]) return; dfs2(son[x],tt); for(long long i=head[x];i;i=e[i].nex) { long long y=e[i].u; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } long long q1(long long x,long long y) { long long ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=querry(1,id[top[x]],id[x]); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ans+=querry(1,id[y],id[x]); return ans; } void tree_modify(long long x,long long v) { modify(1,id[x],id[x]+sz[x]-1,v); } int main() { scanf("%lld%lld",&n,&m); for(long long i=1;i<=n;i++) scanf("%lld",&b[i]); for(long long i=1;i<=n-1;i++) { long long aa,bb; scanf("%lld%lld",&aa,&bb); add(aa,bb); add(bb,aa); } dfs1(1,0,1); dfs2(1,1); build(1,1,n); for(long long i=1;i<=m;i++) { scanf("%lld",&flag); if(flag==1) scanf("%lld%lld",&t,&res),modify(1,id[t],id[t],res); else if(flag==2) scanf("%lld%lld",&t,&res),tree_modify(t,res); else scanf("%lld",&t),printf("%lld\n",q1(1,t)); } return 0; }
洛谷P2486 染色(https://www.luogu.org/problem/P2486)
SDOI的一道题,线段树维护比较麻烦,需要维护区间左右端点的颜色以便合并时判重。
但更麻烦的是在合并链时链两端的判重。
啊这题真的好烦,但绝对是道好题QAQ ,由于有X,Y两个点往上走,所以要维护两条链的端点颜色,这样就需要再维护四个变量。
#include#include #include #include #include using namespace std; const int maxn=101000; int b[maxn],id[maxn],top[maxn],dep[maxn],son[maxn],head[maxn],cul[maxn],sz[maxn],fa[maxn]; int n,m,cnt,num,p,q,aa,bb,cc,dd; int link1,link2,lc,rc; char o; struct pp { int l,r; int lc,rc; int tag,sum; }s[maxn*4]; struct oo { int u; int nex; }e[maxn*2]; void add(int x,int y) { e[++cnt].u=y; e[cnt].nex=head[x]; head[x]=cnt; } void up(int rt) { s[rt].lc=s[rt<<1].lc; s[rt].rc=s[rt<<1|1].rc; s[rt].sum=s[rt<<1].sum+s[rt<<1|1].sum; if(s[rt<<1].rc==s[rt<<1|1].lc) s[rt].sum--; } void down(int rt) { if(s[rt].tag) { s[rt<<1].tag=s[rt<<1|1].tag=s[rt].tag; s[rt<<1].lc=s[rt<<1].rc=s[rt<<1|1].lc=s[rt<<1|1].rc=s[rt].lc; s[rt<<1].sum=s[rt<<1|1].sum=1; s[rt].tag=0; } } void build(int rt,int l,int r) { s[rt].l=l; s[rt].r=r; if(l==r) { s[rt].sum=1; s[rt].lc=s[rt].rc=cul[l]; return; } int mid=(s[rt].l+s[rt].r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); up(rt); } void modify(int rt,int l,int r,int v) { if(s[rt].l>=l&&s[rt].r<=r) { s[rt].lc=s[rt].rc=v; s[rt].sum=s[rt].tag=1; return; } down(rt); int mid=(s[rt].l+s[rt].r)>>1; if(l<=mid) modify(rt<<1,l,r,v); if(r>mid) modify(rt<<1|1,l,r,v); up(rt); } void dfs1(int x,int f,int deep) { fa[x]=f; dep[x]=deep; sz[x]=1; int ms=-1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==f) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if(ms<sz[y]) { son[x]=y; ms=sz[y]; } } } int querry(int rt,int l,int r) { if(l<=s[rt].l&&r>=s[rt].r) { if(l==s[rt].l ) lc=s[rt].lc; if(r==s[rt].r) rc=s[rt].rc; return s[rt].sum; } int ans=0; down(rt); int mid=(s[rt].l+s[rt].r)>>1; if(l<=mid) ans+=querry(rt<<1,l,r); if(r>mid) ans+=querry(rt<<1|1,l,r); if(l<=mid&&r>mid&&s[rt<<1].rc==s[rt<<1|1].lc) ans--; return ans ; } void dfs2(int x,int tt) { id[x]=++num; cul[num]=b[x]; top[x]=tt; if(!son[x]) return; dfs2(son[x],top[x]); for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } void treemodify(int x,int y,int v) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]] ) swap(x,y); modify(1,id[top[x]],id[x],v); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); modify(1,id[y],id[x],v); } int ask(int x,int y) { int ans=0; link1=link2=-1; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y),swap(link1,link2); ans+=querry(1,id[top[x]],id[x]); if(rc==link1) ans--; link1=lc; x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y),swap(link1,link2); ans+=querry(1,id[y],id[x]); if(rc==link1) ans--; if(lc==link2) ans--; return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n-1;i++) { scanf("%d%d",&aa,&bb); add(aa,bb); add(bb,aa); } dfs1(1,0,1); dfs2(1,1); build(1,1,n); for(int i=1;i<=m;i++) { cin>>o; if(o=='C') { scanf("%d%d%d",&aa,&bb,&cc); treemodify(aa,bb,cc); } else { scanf("%d%d",&aa,&bb); cout<<ask(aa,bb); printf("\n"); } } return 0; }
洛谷P2146 软件包管理器(https://www.luogu.org/problem/P2146)
啊挺模板的一道题,用到了区间覆盖的思想。
卸载后权值为0,安装了权值为1,每次询问求一下操作前后的权值差就OK了
#include#include #include #include #include using namespace std; const int MAXN=100010; struct pp { int l,r; int tag,sum; }t[MAXN*4]; struct kk { int u; int nex; }e[MAXN*2]; int a[MAXN],b[MAXN],id[MAXN],sz[MAXN],son[MAXN],top[MAXN],fa[MAXN],dep[MAXN]; int head[MAXN]; int n,m,cnt,num,k,p,q,g,last; void add(int x,int y) { e[++cnt].u=y; e[cnt].nex=head[x]; head[x]=cnt; } int ss(int rt) { return (t[rt].r-t[rt].l+1); } void up(int rt) { t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum; } void down(int rt) { if(t[rt].tag!=-1) { t[rt<<1].sum=t[rt].tag*ss(rt<<1); t[rt<<1|1].sum=t[rt].tag*ss(rt<<1|1); t[rt<<1].tag=t[rt].tag; t[rt<<1|1].tag=t[rt].tag; t[rt].tag=-1; } } void build (int rt,int l,int r) { t[rt].l=l; t[rt].r=r; t[rt].tag=-1; t[rt].sum=0; if(l==r) return; int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); up(rt); } void modify(int rt,int l,int r,int v) { if(t[rt].l>=l&&t[rt].r<=r) { t[rt].sum=v*ss(rt); t[rt].tag=v; return; } down(rt); int mid=(t[rt].l+t[rt].r)>>1; if(l<=mid) modify(rt<<1,l,r,v); if(r>mid) modify(rt<<1|1,l,r,v); up(rt); } int quer(int rt,int l,int r) { if(t[rt].l>=l&&t[rt].r<=r) { return t[rt].sum; } down(rt); int ans=0; int mid=(t[rt].l+t[rt].r)>>1; if(l<=mid) ans+=quer(rt<<1,l,r); if(r>mid) ans+=quer(rt<<1|1,l,r); return ans; } void dfs1(int x,int f,int deep) { dep[x]=deep; fa[x]=f; sz[x]=1; int ms=-1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==f) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if(sz[y]>ms) { ms=sz[y]; son[x]=y; } } } void dfs2(int x,int tt) { id[x]=++num; top[x]=tt; if(!son[x]) return; dfs2(son[x],tt); for(int i=head[x];i;i=e[i].nex) { int y=e[i].u; if(y==son[x]||y==fa[x]) continue; dfs2(y,y); } } int q1(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=quer(1,id[top[x]],id[x]); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ans+=quer(1,id[y],id[x]); return ans; } void m1(int x,int y,int v) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); modify(1,id[top[x]],id[x],v); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); modify(1,id[y],id[x],v); } void tm(int x,int v) { modify(1,id[x],id[x]+sz[x]-1,v); } int tq(int x) { return quer(1,id[x],id[x]+sz[x]-1); } int main() { string o; scanf("%d",&n); for(int i=1;i<=n-1;i++) { scanf("%d",&q); add(i+1,q+1); add(q+1,i+1); } dfs1(1,0,1); dfs2(1,1); build(1,1,n+1); scanf("%d",&m); for(int i=1;i<=m;i++) { cin>>o; scanf("%d",&k); k=k+1; if(o=="install") { last=q1(1,k); m1(1,k,1); g=q1(1,k); printf("%d\n",abs(g-last)); } else { last=tq(k); tm(k,0); g=tq(k); printf("%d\n",abs(g-last)); } } return 0; }