bzoj 4538: [Hnoi2016]网络

来源:互联网 发布:中差评拦截软件 编辑:程序博客网 时间:2024/05/21 10:48

题意:

给一棵树,可以将某条路径打上/删除一个标记,询问一个点,所有打了标记的不经过该点的路径中的最大值。

题解:

一开始想到拆成两条链,dfs序一下,但好像只会维护和。
orz,发现是树链剖分+线段树套堆。
于是就可做了,树剖是将不包含的线段标记出来,在线段树上的每个点上开两个优先队列,分别表示加的值和删的值,然后两个一起pop。标记永久化。
还有些玄学地方,具体见bzoj discuss。
code:

#include<queue>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;struct node{    int y,next;}a[200010];int len=0,last[100010];struct TRnode{    int fa,top,son,tot,dep;}TR[100010];struct trnode{    int lc,rc;    priority_queue<int> q1,q2;}tr[200010];int tot=0,root=0;int ys[100010],z=0;int n,m;void ins(int x,int y){    a[++len].y=y;    a[len].next=last[x];last[x]=len;}void pre_node(int x,int fa){    TR[x].dep=TR[fa].dep+1;TR[x].fa=fa;TR[x].tot=1;    for(int i=last[x];i;i=a[i].next)    {        int y=a[i].y;        if(y==fa) continue;        pre_node(y,x);        if(TR[TR[x].son].tot<=TR[y].tot) TR[x].son=y;        TR[x].tot+=TR[y].tot;    }}void pre_edge(int x,int top){    TR[x].top=top;ys[x]=++z;    if(TR[x].son) pre_edge(TR[x].son,top);    for(int i=last[x];i;i=a[i].next)    {        int y=a[i].y;        if(y==TR[x].fa||y==TR[x].son) continue;        pre_edge(y,y);    }}struct query{    int a,b,v;}q[200010];query t[1000];int num;bool cmp(query a,query b){return a.a<b.a;}void change(int &x,int l,int r,int fl,int fr,int k,int op){    if(!x) x=++tot;    if(l==fl&&r==fr)    {        if(op==1) tr[x].q1.push(k);        else tr[x].q2.push(k);        return;    }    int mid=(l+r)/2;    if(fr<=mid) change(tr[x].lc,l,mid,fl,fr,k,op);    else if(fl>mid) change(tr[x].rc,mid+1,r,fl,fr,k,op);    else change(tr[x].lc,l,mid,fl,mid,k,op),change(tr[x].rc,mid+1,r,mid+1,fr,k,op);}int findans(int x,int l,int r,int k){    if(!x) return -1;    while(!tr[x].q1.empty()&&!tr[x].q2.empty()&&tr[x].q1.top()==tr[x].q2.top())        tr[x].q1.pop(),tr[x].q2.pop();    int mid=(l+r)/2,K;    if(tr[x].q1.empty()) K=-1;    else K=tr[x].q1.top();    if(l==r) return K;    if(k<=mid) return max(K,findans(tr[x].lc,l,mid,k));    return max(K,findans(tr[x].rc,mid+1,r,k));}void solve(int x,int y,int k,int op){    num=0;    int tx=TR[x].top,ty=TR[y].top;    while(tx!=ty)    {        if(TR[tx].dep<TR[ty].dep) swap(x,y),swap(tx,ty);        t[++num].a=ys[tx];t[num].b=ys[x];        x=TR[tx].fa;tx=TR[x].top;    }    if(TR[x].dep<TR[y].dep) swap(x,y);    t[++num].a=ys[y];t[num].b=ys[x];    sort(t+1,t+num+1,cmp);    int p=1;    for(int i=1;i<=num;i++)    {        if(p<t[i].a) change(root,1,n,p,t[i].a-1,k,op);        p=t[i].b+1;    }    if(p<=n) change(root,1,n,p,n,k,op);}int main(){    scanf("%d %d",&n,&m);    for(int i=1;i<n;i++)    {        int x,y;scanf("%d %d",&x,&y);        ins(x,y);ins(y,x);    }    pre_node(1,0);pre_edge(1,1);    for(int i=1;i<=m;i++)    {        int op;scanf("%d",&op);        if(op==0)        {            scanf("%d %d %d",&q[i].a,&q[i].b,&q[i].v);            solve(q[i].a,q[i].b,q[i].v,1);        }        if(op==1)        {            int t;scanf("%d",&t);            solve(q[t].a,q[t].b,q[t].v,2);        }        if(op==2)        {            int x;scanf("%d",&x);            printf("%d\n",findans(root,1,n,ys[x]));        }    }}
原创粉丝点击