• [国家集训队]Tree II


    嘟嘟嘟


    这道题其实还是挺基础的,只不过操作有点多。


    区间乘和区间加按线段树的方式想。
    那么就先要下放乘标记,再下放加标记。但这两个和反转标记是没有先后顺序的。
    对于区间加,sum加的是区间长度(*)lazy标记。但是线段树区间固定,而lct不是,所以还要单独维护一个size。
    还有一点,这个是splay的性质,就是当前节点的sum还要算上自己的权值,而不像线段树完全由子树信息合并而来。
    最最最后一点,得开long long,包括点权。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    const ll mod = 51061;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, q;
    char c[2];
    struct Tree
    {
      int ch[2], fa;
      int siz, rev;
      ll val, sum, add, mul;
    }t[maxn];
    
    In void c_rev(int now)
    {
      swap(t[now].ch[0], t[now].ch[1]);
      t[now].rev ^= 1;
    }
    In void c_mul(int now, ll lzy)
    {
      t[now].sum *= lzy; t[now].sum %= mod;
      t[now].val *= lzy; t[now].val %= mod;
      t[now].mul *= lzy; t[now].mul %= mod;
      t[now].add *= lzy; t[now].add %= mod;
    }
    In void c_add(int now, ll lzy)
    {
      t[now].sum += lzy * (ll)t[now].siz; t[now].sum %= mod;
      t[now].val += lzy; t[now].val %= mod;
      t[now].add += lzy; t[now].add %= mod;
    }
    In void pushdown(int now)
    {
      if(t[now].rev)
      {
    	if(t[now].ch[0]) c_rev(t[now].ch[0]);
        if(t[now].ch[1]) c_rev(t[now].ch[1]);
        t[now].rev = 0;
      }
      if(t[now].mul != 1)
      {
        if(t[now].ch[0]) c_mul(t[now].ch[0], t[now].mul);
        if(t[now].ch[1]) c_mul(t[now].ch[1], t[now].mul);
        t[now].mul = 1;
      }
      if(t[now].add)
      {
        if(t[now].ch[0]) c_add(t[now].ch[0], t[now].add);
        if(t[now].ch[1]) c_add(t[now].ch[1], t[now].add);
        t[now].add = 0;
      }
    }
    In void pushup(int now)
    {
      t[now].siz = t[t[now].ch[0]].siz + t[t[now].ch[1]].siz + 1;
      t[now].sum = (t[t[now].ch[0]].sum + t[t[now].ch[1]].sum + t[now].val) % mod;
    }
    In bool n_root(int now)
    {
      return t[t[now].fa].ch[0] == now || t[t[now].fa].ch[1] == now;
    }
    In void rotate(int x)
    {
      int y = t[x].fa, z = t[y].fa, k = (t[y].ch[1] == x);
      if(n_root(y)) t[z].ch[t[z].ch[1] == y] = x; t[x].fa = z;
      t[y].ch[k] = t[x].ch[k ^ 1]; t[t[y].ch[k]].fa = y;
      t[x].ch[k ^ 1] = y; t[y].fa = x;
      pushup(y), pushup(x);
    }
    int st[maxn], top = 0;
    In void splay(int x)
    {
      int y = x;
      st[top = 1] = y;
      while(n_root(y)) st[++top] = y = t[y].fa;
      while(top) pushdown(st[top--]);
      while(n_root(x))
        {
          int y = t[x].fa, z = t[y].fa;
          if(n_root(y)) rotate(((t[y].ch[0] == x) ^ (t[z].ch[0] == y)) ? x : y);
          rotate(x);
        }
    }
    In void access(int x)
    {
      int y = 0;
      while(x)
        {
          splay(x); t[x].ch[1] = y;
          pushup(x);
          y = x; x = t[x].fa;
        }
    }
    In void make_root(int x)
    {
      access(x); splay(x);
      c_rev(x);
    }
    In int find_root(int x)
    {
      access(x); splay(x);
      while(t[x].ch[0]) pushdown(x), x = t[x].ch[0];
      return x;
    }
    In void split(int x, int y)
    {
      make_root(x);
      access(y); splay(y);
    }
    In void Link(int x, int y)
    {
      make_root(x);
      if(find_root(y) != x) t[x].fa = y;
    }
    In void Cut(int x, int y)
    {
      make_root(x);
      if(find_root(y) == x && t[x].fa == y && !t[x].ch[1])
        t[y].ch[0] = t[x].fa = 0, pushup(y);
    }
    
    int main()
    {
      n = read(); q = read();
      for(int i = 1; i <= n; ++i) t[i].val = t[i].mul = t[i].siz = 1;
      for(int i = 1, x, y; i < n; ++i) x = read(), y = read(), Link(x, y);
      for(int i = 1; i <= q; ++i)
        {	
          scanf("%s", c); int x = read(), y = read();
          if(c[0] == '+') {int d = read(); split(x, y); c_add(y, d);}
          else if(c[0] == '*') {int d = read(); split(x, y); c_mul(y, d);}
          else if(c[0] == '/') split(x, y), write(t[y].sum), enter;
          else
    	  {
    	    Cut(x, y);
    	  	x = read(), y = read();
    	 	Link(x, y);
    	  }
        }
      return 0;
    }
    
  • 相关阅读:
    漫谈二分查找Binary Search (转)
    怎样搭建Android开发平台(转)
    vim控,键盘控的福利,在chrome和firefox中用vim
    用dos命令行执行java程序的方法
    简明 Vim 练级攻略(转)
    vim中文手册,gcc中文手册,gdb中文手册打包赠送
    使用Eclipse平台开发Java程序(转)
    使用Eclipse创建一个Android程序方法
    hdu 1024 Max Sum Plus Plus (最大m子段和)(经典DP)(转)
    sql server2008 表分区
  • 原文地址:https://www.cnblogs.com/mrclr/p/10159466.html
Copyright © 2020-2023  润新知