板子:单点修改+区间查询
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; struct Tree { int l,r; int dat; #define l(x) tree[x].l; #define r(x) tree[x].r; #define d(x) tree[x].dat; }tree[N*4]; void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) {d(p)=a[p];return;} int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1+1,mid+1,r); d(p)=max(d(p<<1),d(p<<1+1)); } void change(int p,int x,int v) { if(l(p)==r(p)) {d(p)=v;return;} int mid=(l(p)+r(p))>>1; if(x<=mid) change(p<<1,x,v); else change(p<<1+1,x,v); d(p)=max(d(p<<1),d(p<<1+1)); } int ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return d(p); int mid=(l(p)+r(p))>>1; int val=-(1<<30); if(mid>=l) val=max(val,ask(p<<1,l,r)); if(mid+1<=r) val=max(val,ask(p<<1+1,l,r)); return val; } int main() { build(1,1,n); change(1,x,v); ask(1,1,n); }
T1:求最大连续子段和(单点修改)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//第一次认真的打线段树的板子.... //第一次拼命wrong的点竟然在建树是的赋值,醉了醉了... #include<bits/stdc++.h> using namespace std; const int N=500010; int n,T,c[N]; struct Tree { int sum,dat,lmax,rmax,l,r; #define l(x) t[x].l #define r(x) t[x].r #define s(x) t[x].sum #define d(x) t[x].dat #define lm(x) t[x].lmax #define rm(x) t[x].rmax }t[N*4]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void push(int p) { s(p)=s(p<<1)+s((p<<1)+1); lm(p)=max(lm(p<<1),s(p<<1)+lm((p<<1)+1)); rm(p)=max(rm((p<<1)+1),s((p<<1)+1)+rm(p<<1)); d(p)=max(max(d(p<<1),d((p<<1)+1)),rm(p<<1)+lm((p<<1)+1)); } inline void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) {s(p)=d(p)=lm(p)=rm(p)=c[l(p)];return;} int mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)+1,mid+1,r); push(p); } inline void change(int p,int x,int v) { if(l(p)==r(p)) {s(p)=d(p)=lm(p)=rm(p)=v;return;} int mid=(l(p)+r(p))>>1; if(x<=mid) change(p<<1,x,v); else change((p<<1)+1,x,v); push(p); } inline Tree ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return t[p]; int mid=(l(p)+r(p))>>1; if(r<=mid) return ask(p<<1,l,r); else if(l>=mid+1) return ask((p<<1)+1,l,r); else { Tree a,b,c; a=ask(p<<1,l,r); b=ask((p<<1)+1,l,r); c.sum=a.sum+b.sum; c.lmax=max(a.lmax,a.sum+b.lmax); c.rmax=max(b.rmax,b.sum+a.rmax); c.dat=max(max(a.dat,b.dat),a.rmax+b.lmax); return c; } } int main() { freopen("1.in","r",stdin); n=read();T=read(); for(register int i=1;i<=n;++i) c[i]=read(); build(1,1,n); while(T--) { int op=read(),x=read(),y=read(); if(op==1) { if(x>y) swap(x,y); printf("%d ",ask(1,x,y).dat); } else if(op==2) change(1,x,y); } return 0;
板子:区间修改+区间查询.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=100010; int n,m,a[N]; struct Tree { int l,r; ll sum,add; #define l(x) t[x].l #define r(x) t[x].r #define sum(x) t[x].sum #define add(x) t[x].add }t[N*4]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void push(int p) { if(add(p)) { sum(p<<1)+=(r(p<<1)-l(p<<1)+1)*add(p); sum((p<<1)+1)+=(r((p<<1)+1)-l((p<<1)+1)+1)*add(p); add(p<<1)+=add(p); add((p<<1)+1)+=add(p); add(p)=0; } } inline void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) {sum(p)=a[l];return;} int mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)+1,mid+1,r); sum(p)=sum(p<<1)+sum((p<<1)+1); } inline void change(int p,int l,int r,ll d) { if(l<=l(p)&&r>=r(p)) { sum(p)+=d*(r(p)-l(p)+1); add(p)+=d; return; } push(p); int mid=(l(p)+r(p))>>1; if(mid>=l) change(p<<1,l,r,d); if(mid+1<=r) change((p<<1)+1,l,r,d); sum(p)=sum(p<<1)+sum((p<<1)+1); } inline ll ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return sum(p); ll val=0; push(p); int mid=(l(p)+r(p))>>1; if(mid>=l) val+=ask(p<<1,l,r); if(mid+1<=r) val+=ask((p<<1)+1,l,r); return val; } int main() { freopen("1.in","r",stdin); n=read();m=read(); for(register int i=1;i<=n;++i) a[i]=read(); build(1,1,n); while(m--) { int op=read(); if(op==1) { int x=read(),y=read(),k=read(); change(1,x,y,k); } else { int x=read(),y=read(); printf("%lld ",ask(1,x,y)); } } return 0; }
T2:
区间修改(+和*)+区间查询;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=500010; int n,m,P,a[N]; struct Tree { int l,r; ll sum,add,mul; #define l(x) t[x].l #define r(x) t[x].r #define sum(x) t[x].sum #define add(x) t[x].add #define mul(x) t[x].mul }t[N*4]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void push(int p) { if(mul(p)!=1) { sum(p<<1)=(sum(p<<1)*mul(p))%P; sum((p<<1)+1)=(sum((p<<1)+1)*mul(p))%P; add(p<<1)=(add(p<<1)*mul(p))%P; add((p<<1)+1)=(add((p<<1)+1)*mul(p))%P; mul(p<<1)=(mul(p<<1)*mul(p))%P; mul((p<<1)+1)=(mul((p<<1)+1)*mul(p))%P; mul(p)=1; } if(add(p)) { sum(p<<1)=(sum(p<<1)+(r(p<<1)-l(p<<1)+1)*add(p))%P; sum((p<<1)+1)=(sum((p<<1)+1)+(r((p<<1)+1)-l((p<<1)+1)+1)*add(p))%P; add(p<<1)=(add(p<<1)+add(p))%P; add((p<<1)+1)=(add((p<<1)+1)+add(p))%P; add(p)=0; } } inline void build(int p,int l,int r) { l(p)=l,r(p)=r;mul(p)=1; if(l==r) {sum(p)=a[l];return;} int mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)+1,mid+1,r); sum(p)=(sum(p<<1)+sum((p<<1)+1))%P; } inline void change1(int p,int l,int r,ll d) { if(l<=l(p)&&r>=r(p)) { sum(p)=(sum(p)*d)%P; add(p)=(add(p)*d)%P; mul(p)=(mul(p)*d)%P; return; } push(p); int mid=(l(p)+r(p))>>1; if(l<=mid) change1(p<<1,l,r,d); if(r>=mid+1) change1((p<<1)+1,l,r,d); sum(p)=(sum(p<<1)+sum((p<<1)+1))%P; } inline void change2(int p,int l,int r,ll d) { if(l<=l(p)&&r>=r(p)) { sum(p)=(sum(p)+(r(p)-l(p)+1)*d)%P; add(p)=(add(p)+d)%P; return; } push(p); int mid=(l(p)+r(p))>>1; if(l<=mid) change2(p<<1,l,r,d); if(r>=mid+1) change2((p<<1)+1,l,r,d); sum(p)=(sum(p<<1)+sum((p<<1)+1))%P; } inline ll ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return sum(p); push(p); int mid=(l(p)+r(p))>>1; ll val=0; if(l<=mid) val=(val+ask(p<<1,l,r))%P; if(r>=mid+1) val=(val+ask((p<<1)+1,l,r))%P; return val; } int main() { freopen("1.in","r",stdin); n=read();m=read();P=read(); for(register int i=1;i<=n;++i) a[i]=read(); build(1,1,n); while(m--) { int op=read(); if(op==1) { int x=read(),y=read(),k=read(); change1(1,x,y,k); } else if(op==2) { int x=read(),y=read(),k=read(); change2(1,x,y,k); } else if(op==3) { int x=read(),y=read(); printf("%lld ",ask(1,x,y)); } } return 0; }
T3:区间最大公约数(单点修改)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=500010; ll n,T,a[N],c[N],b[N]; struct Tree { ll l,r,dat; #define l(x) t[x].l #define r(x) t[x].r #define d(x) t[x].dat }t[N*4]; inline ll read() { ll x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } ll lowbit(ll x) {return x&(-x);} inline void add(ll x,ll k) {for(;x<=n;x+=lowbit(x)) b[x]+=k;} inline ll assk(ll x) { ll ans=0; for(;x;x-=lowbit(x)) ans+=b[x]; return ans; } ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} inline void build(ll p,ll l,ll r) { l(p)=l,r(p)=r; if(l==r) {d(p)=c[l];return;} ll mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)+1,mid+1,r); d(p)=gcd(d(p<<1),d((p<<1)+1)); } inline void change(ll p,ll x,ll v) { if(x>n) return; if(l(p)==r(p)) {d(p)+=v;return;} ll mid=(l(p)+r(p))>>1; if(x<=mid) change(p<<1,x,v); else change((p<<1)+1,x,v); d(p)=gcd(d(p<<1),d((p<<1)+1)); } inline ll ask(ll p,ll l,ll r) { if(l>r) return 0; if(l<=l(p)&&r>=r(p)) return abs(d(p)); ll mid=(l(p)+r(p))>>1; ll vl=0,vr=0; if(l<=mid) vl=ask(p<<1,l,r); if(r>=mid+1) vr=ask((p<<1)+1,l,r); return abs(gcd(vl,vr)); } int main() { freopen("1.in","r",stdin); n=read();T=read(); for(register int i=1;i<=n;++i) a[i]=read(),c[i]=a[i]-a[i-1]; build(1,1,n); while(T--) { char ch; cin>>ch;if(ch=='C') { ll x=read(),y=read(),v=read(); change(1,x,v);add(x,v); change(1,y+1,-v);add(y+1,-v); } else if(ch=='Q') { ll x=read(),y=read(); printf("%lld ",gcd(a[x]+assk(x),ask(1,x+1,y))); } } return 0; }
4:扫描线:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; double Y[N*2],x1,yy1,x2,y2; ll n,cnt; struct ScanLine { double l,r,x; int mark; }line[N*2]; struct Tree { int l,r,sum; double len; #define l(p) t[p].l #define r(p) t[p].r #define sum(p) t[p].sum #define len(p) t[p].len }t[N<<3]; inline bool cmp(ScanLine a,ScanLine b){return a.x<b.x;} inline void build(int p,int l,int r) { l(p)=l,r(p)=r; sum(p)=len(p)=0; if(l==r) return; int mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)+1,mid+1,r); } inline void push(int p) { if(sum(p)) len(p)=Y[r(p)+1]-Y[l(p)]; else len(p)=len(p<<1)+len((p<<1)+1); } inline void change(int p,double l,double r,int c) { if(l<=Y[l(p)]&&r>=Y[r(p)+1]) { sum(p)+=c; push(p); return; } ll mid=(l(p)+r(p))>>1; if(Y[mid]>=l) change(p<<1,l,r,c); if(Y[mid+1]<r) change((p<<1)+1,l,r,c); push(p); } int main() { freopen("1.in","r",stdin); while(cin>>n) { cnt++; if(n==0) break; for(register int i=1;i<=n;++i) { scanf("%lf %lf %lf %lf",&x1,&yy1,&x2,&y2); Y[i*2]=yy1;Y[i*2-1]=y2; line[i*2]=(ScanLine){yy1,y2,x1,1}; line[i*2-1]=(ScanLine){yy1,y2,x2,-1}; } n<<=1; sort(line+1,line+n+1,cmp); sort(Y+1,Y+n+1); int tot=unique(Y+1,Y+n+1)-Y-1; build(1,1,tot-1); double ans=0; for(register int i=1;i<n;++i) { change(1,line[i].l,line[i].r,line[i].mark); ans+=len(1)*(line[i+1].x-line[i].x); } printf("Test case #%d ",cnt); printf("Total explored area: %.2lf ",ans); } return 0; }
最后记得一定要将i枚举到n,为了将线段树信息抵消...
最近又做了巨多线段树的题:
.....上次做完做鸡蛋后就对延迟标记的了解更深了....
这个就是修改还行,直接就全部覆盖,至于每次查询,它问什么我们就求什么,我们保存每个区间的三个信息,区间内的最大连续空位,区间最靠左的连续空位,区间最靠右的连续空位.
至于更新信息嘛就很简单了.最难的时查询时,我们一次考虑构成答案的三种情况.sum(p<<1),那就地柜左子树,sum(p<<1|1)你就递归右子树.rsum(p<<1)+lsum(p<<1|1)那就直接算答案.由于答案要求我们最小,所以我们搜索顺序就要调换一下...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=50010; int n,m; struct Tree { int l,r,lsum,rsum,sum,add; #define lsum(x) t[x].lsum #define rsum(x) t[x].rsum #define l(x) t[x].l #define r(x) t[x].r #define sum(x) t[x].sum #define add(x) t[x].add }t[N<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void pushup(int p) { lsum(p)=lsum(p<<1); if(lsum(p<<1)==r(p<<1)-l(p<<1)+1) lsum(p)+=lsum(p<<1|1); rsum(p)=rsum(p<<1|1); if(rsum(p<<1|1)==r(p<<1|1)-l(p<<1|1)+1) rsum(p)+=rsum(p<<1); sum(p)=max(max(sum(p<<1),sum(p<<1|1)),rsum(p<<1)+lsum(p<<1|1)); } inline void pushdown(int p) { if(add(p)==1) { sum(p<<1)=lsum(p<<1)=rsum(p<<1)=r(p<<1)-l(p<<1)+1; sum(p<<1|1)=lsum(p<<1|1)=rsum(p<<1|1)=r(p<<1|1)-l(p<<1|1)+1; add(p<<1)=1; add(p<<1|1)=1; add(p)=0; } else if(add(p)==-1) { sum(p<<1)=lsum(p<<1)=rsum(p<<1)=0; sum(p<<1|1)=lsum(p<<1|1)=rsum(p<<1|1)=0; add(p<<1)=-1; add(p<<1|1)=-1; add(p)=0; } } inline void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) {sum(p)=rsum(p)=lsum(p)=1;return;} int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); } inline void alter(int p,int l,int r,int op) { if(l<=l(p)&&r>=r(p)) { if(op==1) { sum(p)=lsum(p)=rsum(p)=r(p)-l(p)+1; add(p)=1; } else { sum(p)=lsum(p)=rsum(p)=0; add(p)=-1; } return; } pushdown(p); int mid=l(p)+r(p)>>1; if(l<=mid) alter(p<<1,l,r,op); if(r>=mid+1) alter(p<<1|1,l,r,op); pushup(p); } inline int ask(int p,int x) { if(l(p)==r(p)) return l(p); pushdown(p); int mid=l(p)+r(p)>>1; if(sum(p<<1)>=x) return ask(p<<1,x); else if(rsum(p<<1)+lsum(p<<1|1)>=x) return mid-rsum(p<<1)+1; else if(sum(p<<1|1)>=x) return ask(p<<1|1,x); } int main() { n=read();m=read(); build(1,1,n); for(int i=1;i<=m;++i) { int op=read(); if(op==1) { int x=read(); if(sum(1)>=x) { int s=ask(1,x); printf("%d ",s); alter(1,s,s+x-1,-1); } else printf("0 "); } else { int x=read(),y=read(); alter(1,x,x+y-1,1); } } return 0; }
![](https://img2018.cnblogs.com/common/1467880/202001/1467880-20200115160539571-1645552186.png)
疯狂的在推式子,结果需要暴力修改.
因为每次的开跟,所以1e9最多开5次不变了,所以其实大部分的修改都是无效的.我们修改时就暴力修改子树,当子树修改时已经无影响时,我们打上标记,下次再修改时直接return即可...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; int n,a[N],m; struct Tree { int l,r; ll sum; bool vis; #define l(x) t[x].l #define r(x) t[x].r #define sum(x) t[x].sum #define vis(x) t[x].vis }t[N<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) { sum(p)=a[l]; if(sum(p)==0||sum(p)==1) vis(p)=1; return; } int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); sum(p)=sum(p<<1)+sum(p<<1|1); if(vis(p<<1)&&vis(p<<1|1)) vis(p)=1; } inline ll ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return sum(p); int mid=l(p)+r(p)>>1; ll ans=0; if(l<=mid) ans+=ask(p<<1,l,r); if(r>=mid+1) ans+=ask(p<<1|1,l,r); return ans; } inline void alter(int p,int l,int r) { if(l(p)==r(p)) { sum(p)=sqrt(sum(p)); if(sum(p)==0||sum(p)==1) vis(p)=1; return; } if(vis(p)) return; int mid=r(p)+l(p)>>1; if(l<=mid) alter(p<<1,l,r); if(r>=mid+1) alter(p<<1|1,l,r); sum(p)=sum(p<<1)+sum(p<<1|1); if(vis(p<<1)&&vis(p<<1|1)) vis(p)=1; } int main() { n=read(); for(int i=1;i<=n;++i) a[i]=read(); build(1,1,n); m=read(); for(int i=1;i<=m;++i) { int op=read(),x=read(),y=read(); if(op==1) printf("%lld ",ask(1,x,y)); else alter(1,x,y); } return 0; }
好吧,最后几道就压轴出场了:
这道题真的想写很久了,前置知识一学完就又回来刚这道题...
不过真的咋看不会,看的第一眼,嗯,树上差分,如果z值不大,那我们就可以轻松用数组搞定,之后用dfs合并输出,每次在一个点的cnt[x][z]中选出最大的一个点,这样的复杂度...emmm应该是(nz)的.不过不光是时间过不去,空间也开不下....
之后我就翻开题解,一看他们全部都是权值线段树啊,啥主席树啊,在哪瞎搞,权值线段树我也懂,可为什么要用呢?我是真的不懂.....死劲看....也看不出来....
终于我好像懂了点....权值线段树用数值存次数,简单地说就是一个桶...就像我们以前用的桶排序一样,既然数组开不下,我们完全可以用权值线段树代替,而且查询最大值还是log的
其实仔细想想,没错啊!权值线段树不就只是用权值记录次数吗?我们要找的最大值不也是找所有的数中出现次数最多的吗?之后,就用权值线段树瞎搞....
在合并时用上线段树合并...玄学复杂度....于是乎就这样水过了....不过最后wrong的一个点着实让人不满意...提醒我们权值线段树当出现次数为负值时,不可更新答案...
怎么说呢....真的很高兴.....哈哈哈哈哈哈哈哈.....
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=100010,M=10000010; int n,m,link[N],tot,root[N],cnt; int deep[N],f[N][25],fa[N]; struct edge{int y,next;}a[N<<1]; struct Tree { int lc,rc,dat,mx; #define lc(x) t[x].lc #define rc(x) t[x].rc #define dat(x) t[x].dat #define mx(x) t[x].mx }t[M<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void add(int x,int y) { a[++tot].y=y; a[tot].next=link[x]; link[x]=tot; } inline void bfs() { queue<int>q;q.push(1); deep[1]=1; while(!q.empty()) { int x=q.front();q.pop(); for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(deep[y]) continue; deep[y]=deep[x]+1;q.push(y); f[y][0]=x;fa[y]=x; for(int i=1;i<=20;++i) f[y][i]=f[f[y][i-1]][i-1]; } } } inline int lca(int x,int y) { if(deep[x]<deep[y]) swap(x,y); for(int i=20;i>=0;--i) if(deep[f[x][i]]>=deep[y]) x=f[x][i]; if(x==y) return x; for(int i=20;i>=0;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } inline int build() { cnt++; lc(cnt)=rc(cnt)=dat(cnt)=0; return cnt; } inline void pushup(int p) { if(mx(lc(p))>=mx(rc(p))){mx(p)=mx(lc(p));dat(p)=dat(lc(p));} else{mx(p)=mx(rc(p));dat(p)=dat(rc(p));} } inline void alter(int p,int l,int r,int v,int k) { if(l==r) {mx(p)+=k;if(mx(p)>0) dat(p)=l;return;} int mid=l+r>>1; if(v<=mid) { if(!lc(p)) lc(p)=build(); alter(lc(p),l,mid,v,k); } else { if(!rc(p)) rc(p)=build(); alter(rc(p),mid+1,r,v,k); } pushup(p); } inline int merge(int p,int q,int l,int r) { if(!p) return q; if(!q) return p; if(l==r) { mx(p)+=mx(q); if(mx(p)>0) dat(p)=l; return p; } int mid=l+r>>1; lc(p)=merge(lc(p),lc(q),l,mid); rc(p)=merge(rc(p),rc(q),mid+1,r); pushup(p); return p; } inline void dfs(int x) { for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==fa[x]) continue; dfs(y); root[x]=merge(root[x],root[y],1,N-1); } // printf("x=%d dat(root[1])=%d ",x,dat(root[1])); } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<n;++i) { int x=read(),y=read(); add(x,y);add(y,x); } bfs(); for(int i=1;i<=n;++i) root[i]=build(); for(int i=1;i<=m;++i) { int x=read(),y=read(),z=read(); int d=lca(x,y); alter(root[x],1,N-1,z,1); alter(root[y],1,N-1,z,1); alter(root[d],1,N-1,z,-1); alter(root[fa[d]],1,N-1,z,-1); } dfs(1); for(int i=1;i<=n;++i) printf("%d ",dat(root[i])); return 0; }
这个题,有一说一,确实是树剖的好题....
则么说呢,感觉线段树维护的信息很显然..就是不知道讲树上的节点划分成若干个链后怎么统计答案....
想不通....那只能在每次跳到fa[top[a]]时统计答案。
具体的我们可以将这条链结束时,和即将跳的点颜色比较,因为这些节点就是这些链的分开的节点.....
感觉和区间某些性质相关的题都可以这么做,就是在每次跳时都比较和父亲的属性是否相同.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,m,b[N],link[N],tot; int deep[N],fa[N],top[N],wson[N],dfn[N],pre[N],size[N],m1; struct edge{int y,next;}a[N<<1]; struct Tree { int l,r,sum,lc,rc,lazy; #define l(x) t[x].l #define r(x) t[x].r #define sum(x) t[x].sum #define lc(x) t[x].lc #define rc(x) t[x].rc #define lazy(x) t[x].lazy }t[N<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void add(int x,int y) { a[++tot].y=y; a[tot].next=link[x]; link[x]=tot; } inline void pushup(int p) { sum(p)=sum(p<<1)+sum(p<<1|1); if(rc(p<<1)==lc(p<<1|1)) sum(p)--; lc(p)=lc(p<<1);rc(p)=rc(p<<1|1); } inline void push(int p) { if(lazy(p)) { sum(p<<1)=1; sum(p<<1|1)=1; lc(p<<1)=rc(p<<1)=lazy(p); lc(p<<1|1)=rc(p<<1|1)=lazy(p); lazy(p<<1|1)=lazy(p<<1)=lazy(p); lazy(p)=0; } } inline void build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) {sum(p)=1;lc(p)=rc(p)=b[pre[l]];return;} int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); } inline void dfs1(int x,int father) { size[x]=1; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==father) continue; fa[y]=x;deep[y]=deep[x]+1; dfs1(y,x); size[x]+=size[y]; if(size[y]>size[wson[x]]) wson[x]=y; } } inline void dfs2(int x,int tp) { top[x]=tp; dfn[x]=++m1; pre[m1]=x; if(wson[x]) dfs2(wson[x],tp); for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==fa[x]||y==wson[x]) continue; dfs2(y,y); } } inline void Tree_alter(int p,int l,int r,int k) { if(l<=l(p)&&r>=r(p)) { sum(p)=1; lc(p)=rc(p)=k; lazy(p)=k; return; } push(p); int mid=l(p)+r(p)>>1; if(l<=mid) Tree_alter(p<<1,l,r,k); if(r>=mid+1) Tree_alter(p<<1|1,l,r,k); pushup(p); } inline int Tree_query(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return sum(p); push(p); int ans=0,cnt=0; int mid=l(p)+r(p)>>1; if(l<=mid) ans+=Tree_query(p<<1,l,r),cnt++; if(r>=mid+1) ans+=Tree_query(p<<1|1,l,r),cnt++; if(cnt==2&&rc(p<<1)==lc(p<<1|1)) ans--; return ans; } inline void alter(int a,int b,int k) { while(top[a]!=top[b]) { if(deep[top[a]]<deep[top[b]]) swap(a,b); Tree_alter(1,dfn[top[a]],dfn[a],k); a=fa[top[a]]; } if(deep[a]<deep[b]) swap(a,b); Tree_alter(1,dfn[b],dfn[a],k); } inline int ask(int p,int x) { if(l(p)==r(p)) return lc(p); push(p); int mid=l(p)+r(p)>>1; if(x<=mid) return ask(p<<1,x); else return ask(p<<1|1,x); } inline int query(int a,int b) { int ans=0; while(top[a]!=top[b]) { if(deep[top[a]]<deep[top[b]]) swap(a,b); ans+=Tree_query(1,dfn[top[a]],dfn[a]); if(fa[top[a]]!=0&&ask(1,dfn[top[a]])==ask(1,dfn[fa[top[a]]])) ans--; a=fa[top[a]]; } if(deep[a]<deep[b]) swap(a,b); ans+=Tree_query(1,dfn[b],dfn[a]); return ans; } int main() { n=read();m=read(); for(int i=1;i<=n;++i) b[i]=read(); for(int i=1;i<n;++i) { int x=read(),y=read(); add(x,y);add(y,x); } dfs1(1,0);dfs2(1,1); build(1,1,n); for(int i=1;i<=m;++i) { char c;cin>>c; if(c=='Q') { int x=read(),y=read(); printf("%d ",query(x,y)); } else { int x=read(),y=read(),k=read(); alter(x,y,k); } } return 0; }