[HNOI2016]网络
[HNOI2016]网络
树剖好题...
首先他要求不受此影响的最大值.我们可以将题目中的链的补集都加上一个重要度,这样就可以单点查询最大值了.
之后我们考虑如何给线段树加上一个重要度x,而且要求要能求出最大值.这里就想到STL中的大跟堆,其实set也行吧...
对于线段树中的每一个点都对应一个堆,我们给点加上重要度时,直接让他进去大跟堆即可.
之后怎么考虑撤销,我们如果直接q.pop()的话显然不行.我们考虑再见一个堆,将要删除的数加进去这个堆里.
之后查询时,对比两个堆顶,相同的话都弹出即可.
之后考虑怎么线段树区间覆盖,这里用lazy显然不行...既然如此我们就用标记永久化.
其实简单看一下,标记永久化也没那么复杂,就是讲要覆盖的区间打上标记,在询问时一路累积标记即可.感觉和差分的询问时好像...
这样我们就解决这道题了...好了,到次为止.
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; int n,m,link[N],tot; int dfn[N],pre[N],size[N],wson[N],top[N],deep[N],fa[N],num; struct edge{int y,next;}a[N<<1]; struct shu{int x,y,v;}b[N],c[N]; priority_queue<int>q1[N<<2],q2[N<<2]; struct Tree { int l,r; #define l(x) t[x].l #define r(x) t[x].r }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 bool cmp(shu x,shu y){return x.x<y.x;} inline void add(int x,int y) { a[++tot].y=y; a[tot].next=link[x]; link[x]=tot; } inline void dfs1(int x) { size[x]=1; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==fa[x]) continue; fa[y]=x;deep[y]=deep[x]+1; dfs1(y); size[x]+=size[y]; if(size[y]>size[wson[x]]) wson[x]=y; } } inline void dfs2(int x,int tp) { dfn[x]=++num; pre[num]=x; top[x]=tp; 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 build(int p,int l,int r) { l(p)=l,r(p)=r; if(l==r) return; int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); } inline void Tree_alter(int p,int l,int r,int v,int op) { if(l==l(p)&&r==r(p)) { if(op==1) q1[p].push(v); else q2[p].push(v); return; } int mid=l(p)+r(p)>>1; if(r<=mid) Tree_alter(p<<1,l,r,v,op); else if(l>mid) Tree_alter(p<<1|1,l,r,v,op); else Tree_alter(p<<1,l,mid,v,op),Tree_alter(p<<1|1,mid+1,r,v,op); } inline void solve1(int a,int b,int v,int op) { int o=0; while(top[a]!=top[b]) { if(deep[top[a]]>deep[top[b]]) swap(a,b); c[++o].x=dfn[top[b]];c[o].y=dfn[b]; b=fa[top[b]]; } if(deep[a]>deep[b]) swap(a,b); c[++o].x=dfn[a];c[o].y=dfn[b]; sort(c+1,c+o+1,cmp); //for(int i=1;i<=o;++i) cout<<c[i].x<<' '<<c[i].y<<endl; if(c[1].x!=1) Tree_alter(1,1,c[1].x-1,v,op); for(int i=1;i<o;++i) if(c[i+1].x-c[i].y!=1) Tree_alter(1,c[i].y+1,c[i+1].x-1,v,op); if(c[o].y!=n) Tree_alter(1,c[o].y+1,n,v,op); } inline int Tree_ask(int p,int x) { while(!q1[p].empty()&&!q2[p].empty()&&q1[p].top()==q2[p].top()) q1[p].pop(),q2[p].pop(); int ans=q1[p].empty()?-1:q1[p].top(); if(l(p)==r(p)) return ans; int mid=l(p)+r(p)>>1; if(x<=mid) ans=max(ans,Tree_ask(p<<1,x)); else ans=max(ans,Tree_ask(p<<1|1,x)); return ans; } 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); } dfs1(1);dfs2(1,1); build(1,1,n); // for(int i=1;i<=n;++i) cout<<i<<' '<<dfn[i]<<endl; for(int i=1;i<=m;++i) { int type=read(); if(!type) { int x=read(),y=read(),v=read(); b[i].x=x;b[i].y=y;b[i].v=v; solve1(x,y,v,1); } else if(type==1) { int x=read(); solve1(b[x].x,b[x].y,b[x].v,-1); } else if(type==2) { int x=read(); printf("%d\n",Tree_ask(1,dfn[x])); } } return 0; }