Master of Data Structure Gym - 102220D(虛樹)

題意:給以一顆有n個節點的樹,給你m次操作。n<5e5,m<2000

操作有:對一條鏈加x,異或x,減x,求和,求異或和,求最大值減最小值,求和k最接近的數

思路:因爲m只有2000次,所以需要操作的點不會特別多,可以參考離散化的思想,把重要的點建一顆虛樹,虛樹的大小是o(m)的。原樹除了重要點之後剩下了一些鏈接重要點的鏈,我們可以把這些鏈縮成一個點,因爲這些鏈上每個點的值都是相同的。

新的虛樹就包含了,操作點,操作點的lca,和縮完的點,對每一次操作暴力即可。

#include <bits/stdc++.h>

using namespace std;
#define N 500005
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define add(a,b) ((a+=(b))%=mod)
vector<int>path[N],vir[N];
stack<int>q[N];
int is[N],iss[N],dep[N],w[N],siz[N],fa[N];
ll a[N];
void dfs(int u,int fat,int depth){
    dep[u]=depth;w[u]=u;siz[u]=1;
    int sum=0,pos=-1;
    for(auto to:path[u]){
        if(to==fat)continue;
        dfs(to,u,depth+1);
        if(!iss[to])continue;
        iss[u]|=iss[to];
        sum+=iss[to];
        pos=w[to];
    }
    if(!iss[u])return;
    if(!is[u] &&sum==1){
        if(is[pos])fa[pos]=u;
        else {
            w[u]=pos;
            siz[pos]++;
        }
        return;
    }
    is[u]=1;
    for(auto to:path[u]){
        if(to==fat||!iss[to])continue;
        fa[w[to]]=u;
    }
}
ll op(int u,int v,int f,int k){
    ll res=0,ma=-1e17,mi=1e17;
    while(true){
        if(dep[u]<dep[v])swap(u,v);
        switch(f){
            case 1:a[u]+=k;break;
            case 2:a[u]^=k;break;
            case 3:if(a[u]>k)a[u]-=k;break;
            case 4:res+=a[u]*siz[u];break;
            case 5:res^=((siz[u]&1)?a[u]:0);break;
            case 6:ma=max(ma,a[u]);mi=min(mi,a[u]);res=ma-mi;break;
            case 7:mi=min(mi,abs(a[u]-k));res=mi;
        }
        if(u==v)break;
        u=fa[u];
    }
    return res;
}
int ope[N],l[N],r[N],va[N];
int main()
{
    int T,n,m,x,y;
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        go(i,1,n)path[i].clear(),is[i]=iss[i]=a[i]=0;
        go(i,2,n)scanf("%d%d",&x,&y),path[x].push_back(y),path[y].push_back(x);
        go(i,1,m){
            scanf("%d%d%d",&ope[i],&l[i],&r[i]);
            if(ope[i]<4||ope[i]>6)scanf("%d",&va[i]);
            else va[i]=0;
            is[l[i]]=is[r[i]]=1;iss[l[i]]=iss[r[i]]=1;
        }
        dfs(1,0,1);
        go(i,1,m){
            ll ans=op(l[i],r[i],ope[i],va[i]);
           // cout<<"+++++"<<endl;
            if(ope[i]>3)printf("%lld\n",ans);
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章