[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;
}
View Code

 

posted @ 2020-03-26 12:11  逆天峰  阅读(198)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//