51nod 1782 圣诞树 dsu on tree+splay

题意

ξ 得到了一棵圣诞树,他需要在上面挂满礼物。
ξ 会事先进行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

分析

链上的修改操作我们可以树上差分一下变成点的修改操作。
可以用一棵splay来维护每种颜色的大小顺序,然后用dsu on tree来优化一下就好了。
一开始想打线段树,看了看发现空间不够然后就放弃了。
丧心病狂居然要卡常。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
using  namespace std;

typedef long long LL;
typedef pair<int,int> pi;

const int N=100005;
const int inf=100000;

int n,m,q,fa[N],dep[N],top[N],size[N],root,cnt,last[N],son[N],ans[N],c[N],stack[15];
LL sum[N];
struct edge{int to,next;}e[N*2];
struct tree{int w,s,l,r,fa;}t[N];
vector<pi> vec[N],que[N];

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void pri(int x)
{
    if (!x) {puts("0");return;}
    int t=0;
    while (x) stack[++t]=x%10,x/=10;
    while (t) putchar(stack[t--]+'0');
    puts("");
}

void addedge(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

void dfs1(int x)
{
    dep[x]=dep[fa[x]]+1;size[x]=!size[x]?1:vec[x].size();
    for (int i=last[x];i;i=e[i].next)
    {
        if (e[i].to==fa[x]) continue;
        fa[e[i].to]=x;
        dfs1(e[i].to);
        size[x]+=size[e[i].to];
    }
}

void dfs2(int x,int chain)
{
    top[x]=chain;son[x]=0;
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&size[e[i].to]>size[son[x]]) son[x]=e[i].to;
    if (!son[x]) return;
    dfs2(son[x],chain);
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&e[i].to!=son[x]) dfs2(e[i].to,e[i].to);
}

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

inline void updata(int x)
{
    t[x].w=t[t[x].l].w^t[t[x].r].w^x;
    t[x].s=t[t[x].l].s+t[t[x].r].s+1;
}

inline void rttl(int x)
{
    int y=t[x].r,p=t[x].fa;t[x].r=t[y].l;
    t[t[y].l].fa=x;
    root=x==root?y:root;
    if (x==t[p].l) t[p].l=y;
    else if (x==t[p].r) t[p].r=y;
    t[y].fa=p;
    t[y].l=x;t[x].fa=y;
    updata(x);updata(y);
}

inline void rttr(int x)
{
    int y=t[x].l,p=t[x].fa;t[x].l=t[y].r;
    t[t[y].r].fa=x;
    root=x==root?y:root;
    if (x==t[p].l) t[p].l=y;
    else if (x==t[p].r) t[p].r=y;
    t[y].fa=p;
    t[y].r=x;t[x].fa=y;
    updata(x);updata(y);
}

void splay(int x,int y)
{
    while (t[x].fa!=y)
    {
        int p=t[x].fa,g=t[p].fa;
        if (g==y)
        {
            if (x==t[p].l) rttr(p);
            else rttl(p);
            return;
        }
        if (x==t[p].l)
            if (p==t[g].l) rttr(g),rttr(p);
            else rttr(p),rttl(g);
        else
            if (p==t[g].r) rttl(g),rttl(p);
            else rttl(p),rttr(g);
    }
}

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

inline void ins(int d)
{
    int x=root,y;
    while (x)
        if (cmp(d,x)) y=x,x=t[x].l;
        else y=x,x=t[x].r;
    if (cmp(d,y)) t[y].l=d;
    else t[y].r=d;
    t[d].fa=y;splay(d,0);
}

inline void del(int d)
{
    splay(d,0);
    int nx=t[d].r,ls=t[d].l;
    while (t[nx].l) nx=t[nx].l;
    while (t[ls].r) ls=t[ls].r;
    splay(nx,0);
    if (!ls) t[nx].l=t[d].fa=0,updata(nx);
    else splay(ls,nx),t[ls].r=t[d].fa=0,rttr(nx);
}

int query(int k)
{
    int x=root,y;k=min(k+1,t[x].s);
    while (x)
        if (t[t[x].l].s+1==k) break;
        else if (t[t[x].l].s+1>k) x=t[x].l;
        else k-=t[t[x].l].s+1,x=t[x].r;
    splay(x,0);
    return t[t[x].l].w;
}

void work(int x,int op)
{
    int w=c[x];
    for (int i=0;i<vec[w].size();i++)
    {
        int p=vec[w][i].first,q=vec[w][i].second;
        if (sum[q]) del(q);
        sum[q]+=p*op;
        if (sum[q]) ins(q);
    }
}

void solve(int x)
{
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&e[i].to!=son[x]) solve(e[i].to),work(e[i].to,-1);
    if (son[x]) solve(son[x]);
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&e[i].to!=son[x]) work(e[i].to,1);
    work(x,1);
    for (int i=0;i<que[x].size();i++) ans[que[x][i].second]=query(que[x][i].first);
    for (int i=last[x];i;i=e[i].next)
    {
        if (e[i].to==fa[x]) continue;
        if (vec[c[x]].size()<vec[c[e[i].to]].size()) swap(c[x],c[e[i].to]);
        for (int j=0;j<vec[c[e[i].to]].size();j++) vec[c[x]].pb(vec[c[e[i].to]][j]);
        vec[c[e[i].to]].clear();
    }
}

int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y);
    }
    dfs1(1);dfs2(1,1);
    m=read();
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),a=read(),b=read(),lca=get_lca(x,y);
        vec[x].pb(mp(a,b));vec[y].pb(mp(a,b));vec[lca].pb(mp(-a,b));
        if (fa[lca]) vec[fa[lca]].pb(mp(-a,b));
    }
    dfs1(1);dfs2(1,1);
    q=read();
    for (int i=1;i<=q;i++)
    {
        int x=read(),y=read();
        que[x].pb(mp(y,i));
    }
    root=inf+1;sum[root]=(LL)inf*inf;
    for (int i=1;i<=n;i++) c[i]=i;
    solve(1);
    for (int i=1;i<=q;i++) pri(ans[i]);
    return 0;
}
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值