• 题解报告——[国家集训队]Tree II


    传送门

    题目描述

    一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:

    • + u v c:将u到v的路径上的点的权值都加上自然数c;

    • - u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;

    • * u v c:将u到v的路径上的点的权值都乘上自然数c;

    • / u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

    输入输出格式

    输入格式:

    第一行两个整数n,q

    接下来n-1行每行两个正整数u,v,描述这棵树

    接下来q行,每行描述一个操作

    输出格式:

    对于每个/对应的答案输出一行

    输入输出样例

    输入样例#1: 复制
    3 2
    1 2
    2 3
    * 1 3 4
    / 1 1
    输出样例#1: 复制
    4
    

    说明

    10%的数据保证,1<=n,q<=2000

    另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

    另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

    100%的数据保证,1<=n,q<=10^5,0<=c<=10^4


    【思路分析】

    算是学OI以来的第一道黑题了(几周前A了后就说要写个博客纪念一下,今天算是有时间了)。。。。

    其实这道题是一道稍微提升了一点的LCT模板题,就是多了一个乘法,我们只需要按照加乘线段树的思路,保证先传乘法标记再传加法标记,然后就好了。

    发现要是真的黑题难题真的很恐怖,这道题不考思维就考仔细,GG。。。具体看代码,不过可能压行之后变得比较清奇,可以复制下来,缩进之后再看。

    【代码实现】

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 using namespace std;
     5 const unsigned int maxn=1e5+5;
     6 const unsigned int mod=51061;
     7 struct sd{
     8     unsigned int son[2],fa,rev,siz;
     9 }t[maxn];
    10 unsigned int val[maxn],sum[maxn],mul[maxn],add[maxn];
    11 bool isroot(unsigned int v) {return t[t[v].fa].son[0]!=v&&t[t[v].fa].son[1]!=v;}
    12 bool getson(unsigned int v) {return t[t[v].fa].son[1]==v;}
    13 void turn(unsigned int v) {if(!v)return;swap(t[v].son[0],t[v].son[1]);t[v].rev^=1;}
    14 void goadd(unsigned int v,unsigned int gg) {if(!v)return;add[v]=(add[v]+gg)%mod,val[v]=(val[v]+gg)%mod,sum[v]=(sum[v]+t[v].siz*gg)%mod;}
    15 void gomul(unsigned int v,unsigned int gg) {if(!v)return;mul[v]=(mul[v]*gg)%mod,add[v]=(add[v]*gg)%mod,val[v]=(val[v]*gg)%mod,sum[v]=(sum[v]*gg)%mod;}
    16 void update(unsigned int v) {unsigned int ls=t[v].son[0],rs=t[v].son[1];t[v].siz=t[ls].siz+t[rs].siz+1,sum[v]=(sum[ls]+sum[rs]+val[v])%mod;}
    17 void pushdown(unsigned int v) 
    18 {
    19     if(mul[v]!=1) gomul(t[v].son[0],mul[v]),gomul(t[v].son[1],mul[v]),mul[v]=1;
    20     if(add[v]) goadd(t[v].son[0],add[v]),goadd(t[v].son[1],add[v]),add[v]=0;
    21     if(t[v].rev) turn(t[v].son[0]),turn(t[v].son[1]),t[v].rev=0; 
    22 }
    23 void push(unsigned int v) {if(!isroot(v)) push(t[v].fa);pushdown(v);}
    24 void rotate(unsigned int v)
    25 {
    26     unsigned int ff=t[v].fa,gff=t[ff].fa,which=getson(v);
    27     if(!isroot(ff)) t[gff].son[t[gff].son[1]==ff]=v;
    28     t[ff].son[which]=t[v].son[1-which],t[ff].fa=v;
    29     if(t[v].son[1-which]) t[t[v].son[1-which]].fa=ff;
    30     t[v].son[1-which]=ff,t[v].fa=gff;
    31     update(ff),update(v);
    32 }
    33 void splay(unsigned int v)
    34 {
    35     push(v);
    36     while(!isroot(v))
    37     {
    38         if(!isroot(t[v].fa)) rotate((getson(v)==getson(t[v].fa))?t[v].fa:v);
    39         rotate(v);
    40     }
    41     update(v);
    42 }
    43 void access(unsigned int v)
    44 {
    45     for(unsigned int y=0;v;v=t[y=v].fa)
    46     splay(v),t[v].son[1]=y,update(v);
    47 }
    48 void mroot(unsigned int v) {access(v),splay(v),turn(v);}
    49 void split(unsigned int a,unsigned int b) {mroot(a),access(b),splay(b);}
    50 unsigned int findroot(unsigned int v)
    51 {
    52     access(v),splay(v),push(v);
    53     while(t[v].son[0]) v=t[v].son[0];
    54     return v;
    55 }
    56 void link(unsigned int a,unsigned int b) {mroot(a),t[a].fa=b;}
    57 void cut(unsigned int a,unsigned int b) {split(a,b),t[b].son[0]=t[a].fa=0,update(b);}
    58 int main()
    59 {
    60     unsigned int n,m,a,b,c,d;
    61     scanf("%d%d",&n,&m);
    62     fill(val+1,val+1+n,1);
    63     fill(mul+1,mul+1+n,1);
    64     fill(sum+1,sum+1+n,1);
    65     for(unsigned int i=1;i<n;i++)
    66     scanf("%d%d",&a,&b),link(a,b);
    67     char ord[3];
    68     for(unsigned int i=1;i<=m;i++)
    69     {
    70         scanf("%s%d%d",ord,&a,&b);
    71         if(ord[0]=='+') scanf("%d",&c),split(a,b),goadd(b,c);
    72         if(ord[0]=='-') scanf("%d%d",&c,&d),cut(a,b),link(c,d);
    73         if(ord[0]=='*') scanf("%d",&c),split(a,b),gomul(b,c);
    74         if(ord[0]=='/') split(a,b),printf("%d
    ",sum[b]);
    75     }
    76     return 0;
    77 }
  • 相关阅读:
    Selenium入门15 截图
    selenium入门14 窗口切换
    Locust的官网及安装
    命令行输入Jmeter提示不是内部或外部命令,处理方式:添加环境变量
    python pip安装报错python setup.py egg_info failed with error code 1
    Selenium入门13 cookie的增删改查
    Selenium入门12 鼠标和键盘事件
    Selenium入门11 滚动条控制(通过js)
    Selenium入门10 弹出框的处理 switch_to.alert
    Selenium入门9 上传文件
  • 原文地址:https://www.cnblogs.com/genius777/p/9189234.html
Copyright © 2020-2023  润新知