zoukankan      html  css  js  c++  java
  • BZOJ2759: 一个动态树好题

    n<=30000个同余方程:$x_iequiv k_i*x_{p_i}+b_i (mod 10007)$。m<=100000个操作:一、修改某个不等式的$k_i,p_i,b_i$,二、查询某个变量的值。无解-1,无穷解-2.

    极其好玩的一道题。不像某些“绝世好题”实际是水题。。

    首先按依赖关系可以建成基环树啦,因为n个点,每个点1条出边嘛。

    错误!是基环森林。因为忽略了这个,所以本地找别人代码对拍时造数据也是造成一棵基环树,查了将近5h才发现这回事。。

    很好。

    要求解的话,肯定先从那个环入手,环上算出某个点的值,然后一路推下去即可。可以先列个简单点的东西:如果有同余方程组

    $x_1equiv k_1*x_{2}+b_1$

    $x_2equiv k_2*x_{3}+b_2$
    ......
    $x_nequiv k_n*x_{1}+b_n$

    乱搞+不完全归纳+YY+找规律可得:$x_1=prod_{i=1}^{n}k_i x_1+sum_{i=1}^{n}b_iprod_{j=1}^{i-1}k_j$。这两坨系数可以用可合并的数据结构维护。

    那写到这里自然会选择LCT啦(因为题目说的)。

    首先基环树的常见套路:不换根,然后在根节点(有向图,这个所谓的根节点一定在环上)那里存一个东西记基环树比普通树多出来的那条边。我把他叫做$biu$,因为他就是突然出现的,就有一种$biu$的感觉,是不是很生动啊!那相应的$cut$和$link$函数也要改改,如果要把$x$和其父$y$砍掉,如果$y$是$x$的$biu$,那就$x$的$biu$清零,否则照正常操作$cut$。$link$同理,但记得如果照正常套路$link$的话$x$的$biu$要清零,下面会说。

    来看修改操作。由于要变信息所以把他$access+splay$后直接换信息再$up$最方便。然后来改爸爸,首先和原爸爸$cut$掉,然后和新爸爸$link$上。等会,这里原来有条$biu$边的,操作完之后可能$biu$边不$biu$了,也就是可能环上除了$biu$的一条边被$cut$了,那就$link$一下他(被修改点)所在的树的根节点以及根节点的$biu$,如果真的发生了这种情况,在$link$那里直接$biu$清零并将之连上。

    然后询问。先找到真正的根节点(不是辅助splay树上的)$root$的$biu$,$access(biu)$,然后把那系数整理出来带进扩欧求解,有解的话就求出$root$的值,然后$access$查询点再$splay(root)$,$root$的右儿子上的系数就是用$root$的值求询问点的值的对应系数。

      1 #include<string.h>
      2 #include<stdlib.h>
      3 #include<stdio.h>
      4 #include<math.h>
      5 //#include<assert.h>
      6 #include<algorithm> 
      7 #include<iostream>
      8 //#include<bitset>
      9 using namespace std;
     10 
     11 int n,m;
     12 #define maxn 30011
     13 const int mod=1e4+7;
     14 int exgcd(int a,int b,int &x,int &y)
     15 {
     16     if (!b) {x=1; y=0; return a;}
     17     else
     18     {
     19         int tmp=exgcd(b,a%b,y,x);
     20         y-=a/b*x; return tmp;
     21     }
     22 }
     23 int solve(int a,int b)
     24 {
     25     b=-b;
     26     if (a==0)
     27     {
     28         if (b==0) return -2;
     29         else return -1;
     30     }
     31     if (a<0) {a=-a; b=-b;}
     32     if (b<0) b+=mod;
     33     int x,y;exgcd(a,mod,x,y);
     34     x=((1ll*b*x%mod)+mod)%mod;
     35     return x;
     36 }
     37 
     38 struct LCT
     39 {
     40     struct Node
     41     {
     42         int fa,son[2];
     43         int biu;
     44         int k,b,kk,bb;
     45     }a[maxn];
     46     LCT() {a[0].k=a[0].kk=1;}
     47     void makeatree(int id,int k,int b)
     48     {
     49         a[id].fa=a[id].son[0]=a[id].son[1]=a[id].biu=0;
     50         a[id].k=a[id].kk=k; a[id].b=a[id].bb=b;
     51     }
     52     void up(int x)
     53     {
     54         if (!x) return;
     55         int &p=a[x].son[0],&q=a[x].son[1];
     56         a[x].kk=a[p].kk*1ll*a[x].k%mod*a[q].kk%mod;
     57         a[x].bb=a[q].bb+1ll*a[x].b*a[q].kk%mod+1ll*a[p].bb*a[q].kk%mod*a[x].k%mod; a[x].bb%=mod;
     58     }
     59     bool isroot(int x)
     60     {
     61         if (!a[x].fa) return 1;
     62         return (a[a[x].fa].son[0]!=x && a[a[x].fa].son[1]!=x);
     63     }
     64     void rotate(int x)
     65     {
     66         const int y=a[x].fa,z=a[y].fa;
     67         bool w=(x==a[y].son[0]);
     68         a[x].fa=z;
     69         if (!isroot(y)) a[z].son[y==a[z].son[1]]=x;
     70         a[y].son[w^1]=a[x].son[w];
     71         if (a[x].son[w]) a[a[x].son[w]].fa=y;
     72         a[x].son[w]=y;
     73         a[y].fa=x;
     74         up(y); up(z);
     75     }
     76     void splay(int x)
     77     {
     78         if (!x) return;
     79         while (!isroot(x))
     80         {
     81             const int y=a[x].fa,z=a[y].fa;
     82             if (!isroot(y))
     83             {
     84                 if ((y==a[z].son[0])^(x==a[y].son[0])) rotate(x);
     85                 else rotate(y);
     86             }
     87             rotate(x);
     88         }
     89         up(x);
     90     }
     91     void access(int x)
     92     {
     93         int y=0,tmp=x;
     94         while (x) {splay(x); a[x].son[1]=y; up(x); y=x; x=a[x].fa;}
     95         splay(tmp);
     96     }
     97     int findroot(int x)
     98     {
     99         while (a[x].fa) x=a[x].fa;
    100         return x;
    101     }
    102     void link(int x,int y)
    103     {
    104         if (!y) return;
    105         if (findroot(x)==findroot(y)) a[x].biu=y;
    106         else
    107         {
    108             a[x].biu=0;
    109             access(x);
    110             a[x].fa=y;
    111         }
    112     }
    113     void cut(int x,int y)
    114     {
    115         if (y==a[x].biu) a[x].biu=0;
    116         else
    117         {
    118             access(x);
    119             if (a[x].son[0]) a[a[x].son[0]].fa=0;
    120             a[x].son[0]=0; up(x);
    121         }
    122     }
    123     void modify(int x,int y,int z,int k,int b)
    124     {
    125         access(x);
    126         a[x].k=k; a[x].b=b; up(x);
    127         int root=x; while (a[root].son[0]) root=a[root].son[0];
    128         cut(x,y); link(root,a[root].biu); link(x,z);
    129     }
    130     int query(int x)
    131     {
    132         int root=findroot(x);
    133         while (a[root].son[0]) root=a[root].son[0]; splay(root);
    134         int y=a[root].biu; access(y);
    135         int tmp=solve(a[y].kk-1,a[y].bb);
    136         if (tmp<0) return tmp;
    137         tmp=(1ll*tmp*a[root].k+a[root].b)%mod;
    138         if (x==root) return tmp;
    139         access(x);
    140         splay(root);
    141         y=a[root].son[1];
    142         return (a[y].kk*1ll*tmp+a[y].bb)%mod;
    143     }
    144 }t;
    145 
    146 int p[maxn];
    147 int main()
    148 {
    149     scanf("%d",&n);
    150     for (int i=1,x,y;i<=n;i++)
    151     {
    152         scanf("%d%d%d",&x,&p[i],&y);
    153         t.makeatree(i,x,y);
    154     }
    155     for (int i=1;i<=n;i++) t.link(i,p[i]);
    156     scanf("%d",&m);
    157     int x,y,z,w; char c;
    158     while (m--)
    159     {
    160         while ((c=getchar())!='A' && c!='C');
    161         if (c=='A')
    162         {
    163             scanf("%d",&x);
    164             printf("%d
    ",t.query(x));
    165         }
    166         else
    167         {
    168             scanf("%d%d%d%d",&x,&y,&z,&w);
    169             t.modify(x,p[x],z,y,w);
    170             p[x]=z;
    171         }
    172     }
    173     return 0;
    174 }
    View Code
  • 相关阅读:
    C#将方法作为参数传递(用委托接收方法)
    C#委托
    ASP.NET Identity系列教程-4【Identity高级技术】
    ASP.NET Identity系列教程-3【运用ASP.NET Identity】
    ASP.NET Identity系列教程-2【Identity入门】
    claim、claimsidentity、claimsprincipal
    Entity Framework的几种初始化器
    微信小程序环境准备
    ESLint那些坑
    absolute imports should come before relative imports import/first
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8308377.html
Copyright © 2011-2022 走看看