51nod1782 圣诞树 dsu on tree+splay

15 篇文章 0 订阅
9 篇文章 0 订阅

Description


ξ 得到了一棵圣诞树,他需要在上面挂满礼物。
ξ 会事先进行m个操作,每次在一条链(u[i],v[i])上的每个点上挂上a[i]个种类为b[i]的礼物。
一个点的k-美观度这样计算:把这个点上的所有种类的礼物按照个数从小到大排序,如果个数一样就按照种类从小到大排。
它的k-美观度就是排好序后前k种礼物种类的xor值(如果礼物种类不足k种,就把这个点上所有礼物的种类xor起来)。
接下来给Q个询问,给定w[i],k[i],求点w[i]的k[i]-美观度。

1≤n,Q,m,a[i],b[i],k[i]≤100000,1≤u[i],v[i],w[i]≤n

Solution


非常愧疚,今天又双叒叕垫底了

注意到维护前k大以及他们的异或和可以用线段树或平衡树。我们对于一个修改就拆成a、b、lca,然后离线询问做dsu on tree就行了

具体做法就是我们对于需要维护的全局数据结构,每次先做轻儿子并清空数据结构。然后我们做重儿子不清空,做完所有轻儿子并插入自己求出当前点询问的答案
注意挂在点上的修改也需要向上合并,修改数量的时候需要删除并重新插入

非常难写,而且需要卡一卡

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fi first
#define se second

typedef std:: pair <int,int> pair;
typedef long long LL;
const int N=200005;
const int E=400005;

std:: vector <pair> q[N];
std:: vector <pair> rec[N];

struct treeNode {int son[2],fa,size,sum;} t[N];
struct edge {int y,next;} e[E];

int size[N],mx[N],fa[N],root;
int ls[N],edCnt;
int ans[N],dep[N],id[N],bl[N];
LL sum[N];

inline int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

inline void write(int x) {
    if (x>9) write(x/10);
    putchar(x%10+'0');
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

inline void push_up(int now) {
    t[now].sum=t[t[now].son[0]].sum^t[t[now].son[1]].sum^now;
    t[now].size=t[t[now].son[0]].size+t[t[now].son[1]].size+1;
}

void rotate(int x) {
    int y=t[x].fa; int z=t[y].fa;
    int k=t[y].son[1]==x;
    t[x].fa=z; t[z].son[t[z].son[1]==y]=x;
    t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
    t[y].fa=x; t[x].son[!k]=y;
    push_up(y); push_up(x);
}

void splay(int x,int goal) {
    while (t[x].fa!=goal) {
        int y=t[x].fa; int z=t[y].fa;
        if (z!=goal) {
            if ((t[y].son[1]==x)^(t[z].son[1]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if (!goal) root=x;
}

void dfs1(int now) {
    size[now]=(!size[now])?(1):(rec[now].size());
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now]) continue;
        fa[e[i].y]=now; dep[e[i].y]=dep[now]+1;
        dfs1(e[i].y); size[now]+=size[e[i].y];
    }
}

void dfs2(int now,int up) {
    bl[now]=up; mx[now]=0;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&size[e[i].y]>size[mx[now]]) mx[now]=e[i].y;
    }
    if (!mx[now]) return ;
    dfs2(mx[now],up);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&e[i].y!=mx[now]) dfs2(e[i].y,e[i].y);
    }
}

bool cmp(int x,int y) {
    return sum[x]>sum[y]||sum[x]==sum[y]&&x>y;
}

void ins(int x) {
    int now=root,y;
    while (now) y=now,now=t[now].son[cmp(x,now)];
    t[x]=(treeNode) {{0,0},y,1,x};
    t[y].son[cmp(x,y)]=x;
    splay(x,0);
}

void del(int x) {
    splay(x,0);
    int pre=t[x].son[0],nex=t[x].son[1];
    while (t[pre].son[1]) pre=t[pre].son[1];
    while (t[nex].son[0]) nex=t[nex].son[0];
    splay(nex,0);
    if (pre) {
        splay(pre,nex);
        t[x].fa=t[pre].son[1]=0;
        push_up(pre); push_up(nex);
    } else {
        t[x].fa=t[nex].son[0]=0;
        push_up(nex);
    }
}

int get_lca(int x,int y) {
    while (bl[x]!=bl[y]) {
        if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
        x=fa[bl[x]];
    }
    if (dep[x]<dep[y]) return x;
    return y;
}

int query(int k) {
    int now=root; k=std:: min(k+1,t[root].size);
    while (now) {
        if (t[t[now].son[0]].size+1==k) break;
        else if (t[t[now].son[0]].size>=k) now=t[now].son[0];
        else {
            k-=t[t[now].son[0]].size+1;
            now=t[now].son[1];
        }
    }
    splay(now,0);
    return t[t[now].son[0]].sum;
}

void modify(int x,int opt) {
    int tmp=id[x];
    for (int i=0;i<rec[tmp].size();i++) {
        int a=rec[tmp][i].se,b=rec[tmp][i].fi;
        if (sum[a]) del(a);
        sum[a]+=opt*b;
        if (sum[a]) ins(a);
    }
}

void solve(int now) {
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&e[i].y!=mx[now]) {
            solve(e[i].y);
            modify(e[i].y,-1);
        }
    }
    if (mx[now]) solve(mx[now]);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&e[i].y!=mx[now]) {
            modify(e[i].y,1);
        }
    }
    modify(now,1);
    for (int i=0;i<q[now].size();i++) {
        ans[q[now][i].se]=query(q[now][i].fi);
    }
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now]) continue;
        if (rec[id[now]].size()<rec[id[e[i].y]].size()) std:: swap(id[now],id[e[i].y]);
        for (int j=0;j<rec[id[e[i].y]].size();j++) rec[id[now]].push_back(rec[id[e[i].y]][j]);
        rec[id[e[i].y]].clear();
    }
}

int main(void) {
    freopen("data.in","r",stdin);
    freopen("myp.out","w",stdout);
    int n=read();
    rep(i,2,n) add_edge(read(),read());
    dfs1(1); dfs2(1,1);
    int m=read();
    rep(i,1,m) {
        int x=read(),y=read(),a=read(),b=read();
        int lca=get_lca(x,y);
        rec[lca].push_back(pair(-a,b));
        if (fa[lca]) rec[fa[lca]].push_back(pair(-a,b));
        rec[x].push_back(pair(a,b));
        rec[y].push_back(pair(a,b));
    }
    dfs1(1); dfs2(1,1);
    int T=read();
    rep(i,1,T) {
        int x=read(),y=read();
        q[x].push_back(pair(y,i));
    }
    rep(i,1,n) id[i]=i;
    root=N-1; t[root]=(treeNode) {{0,0},0,1,N-1}; sum[N-1]=(LL)(N-1)*(N-1);
    solve(1);
    rep(i,1,T) {
        write(ans[i]); puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值