【BZOJ - 2243】 SDOI2011 染色

    · 蒟蒻题解, 大神轻虐

    · 各种丑代码

    · 各种绕弯子



    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2243


    Delayyy君吐槽这题本机测比OJ快一倍……

    于是就去写了写.

    树链剖分 or LCT , 各种乱搞.

    本机:树链剖分4s+, LCT 8s+ (太懒了直接代入结构体……各种萎)

    OJ :树链剖分4s+, LCT 10s+

    ……我是没什么意见啦

    但Delayyy君也是10s+ 本机却只有6s

    OJ 的 O2- 抽风了, 诶?

    

    非常非常……裸的代码题.

    树链剖分或者LCT都能水过. 诶不知道 ? 度娘文库里有的是……我就不摆出来了 (还是因为懒...)

    不过今天写的时候发现了一些问题……

        1、子树信息pushdown.    这个原来一直写revroot, 也就是先找到根然后pushdown下来再旋上去. 不过今天突然想到压根就没那必要吧……

              只需要在rotate操作里先 pushdown (f[x]), 然后 pushdown(x) 就可以了.

        2、关于树的遍历. 本机上Delayyy君被某条链爆栈了……改BFS即可过. LCT因为初始化只需要保存父节点, 所以以后还是用BFS算了……

              以防出题人节操丧失. 

        3、updateupdate_size 为啥一定要写啊我> <~ 有的时候不是根本没必要的么......


     代码以下, 版本 1 树链剖分, 版本 2 LCT.


    

#include <cstdio>
#include <cstdlib>
#include <algorithm>
char ch;
#define max(A, B)
#define son (k << 1)
#define mid ((l + r) >> 1)
#define gs (ch < '0' || ch > '9')
int getint() { int wis = 0; ch = getchar(); while (gs) ch = getchar(); while (!gs) wis = wis * 10 + ch - '0', ch = getchar(); return wis; }
const int ys = 300010;
using namespace std;

bool t[ys];
int n, m, nowp, sg, x, y, co;
int size[ys], da[ys], f[ys], up[ys], point[ys], v[ys], d[ys];
int g[ys], next[ys * 2], c[ys * 2], col[ys], push[ys * 4]; 

struct Lek
{
    int left, right, tot;
}   p[ys * 4];
void dfs(int z)
{
    t[z] = true;  size[z] = 1;  int w = 0;  
    for (int x = g[z]; x; x = next[x])
      if (!t[c[x]])  
        if (dfs(c[x]), size[z] += size[c[x]], size[c[x]] > w)
          point[z] = x, w = size[c[x]];    
}
void mak(int z, int dt)
{
    t[z] = false;   v[++sg] = z;  da[z] = sg;  f[z] = nowp;   d[z] = dt; 
    if (point[z])  mak(c[point[z]], dt);
    for (int x = g[z]; x; x = next[x])
      if (t[c[x]])  up[c[x]] = z, nowp = c[x], mak(c[x], dt + 1);
}
void marge(Lek &a, Lek b)
{
    a.tot += b.tot;
    if (a.left == b.right)  a.tot--;
    if (!a.right)  a.right = b.right;
    if (b.left)  a.left = b.left; 
}
Lek build(int l, int r, int k)
{
    if (l == r)  return p[k] = (Lek){col[v[l]], col[v[l]], 1};
    p[k] = build(mid + 1, r, son + 1);
    return marge(p[k], build(l, mid, son)), p[k]; 
}
void pus(int k)
{
    if (push[k])  
    p[son].right = p[son].left = p[son + 1].right = p[son + 1].left = push[k],
    p[son].tot = p[son + 1].tot = 1, push[son + 1] = push[son] = push[k], push[k] = 0;
}
Lek tot(int x, int y, int l, int r, int k)
{
    pus(k);
    if (y < l  ||  x > r)  return (Lek){0, 0, 0};
    if (x <= l  &&  y >= r)  return p[k];
    Lek q = tot(x, y, mid + 1, r, son + 1);
    return marge(q, tot(x, y, l, mid, son)), q; 
}
void cov(int x, int y, int c, int l, int r, int k)
{
    if (y < l  ||  x > r)  return;  pus(k);
    if (x <= l  &&  y >= r)  p[k] = (Lek){c, c, 1}, push[k] = c;
    else  cov(x, y, c, l, mid, son), cov(x, y, c, mid + 1, r, son + 1),
          p[k] = p[son + 1], marge(p[k], p[son]); 
}
int query(int x, int y)
{
    Lek y_tot = {0, 0, 0}, x_tot = {0, 0, 0};
    while (f[x] != f[y])
      if (d[f[x]] < d[f[y]])  marge(y_tot, tot(da[f[y]], da[y], 1, n, 1)), y = up[f[y]];
      else  marge(x_tot, tot(da[f[x]], da[x], 1, n, 1)), x = up[f[x]];  
    if (da[x] > da[y]) return swap(y_tot.left, y_tot.right), marge(x_tot, tot(da[y], da[x], 1, n, 1)), marge(x_tot, y_tot), x_tot.tot;
    else  return swap(x_tot.left, x_tot.right), marge(y_tot, tot(da[x], da[y], 1, n, 1)), marge(y_tot, x_tot), y_tot.tot;
}
void change(int x, int y, int c)
{
    while (f[x] != f[y])
      if (d[f[x]] < d[f[y]])  cov(da[f[y]], da[y], c, 1, n, 1), y = up[f[y]];
      else  cov(da[f[x]], da[x], c, 1, n, 1), x = up[f[x]];
    if (da[x] > da[y])  swap(x, y);
    cov(da[x], da[y], c, 1, n, 1);
}
void add(int x, int y)
{
    c[++sg] = y, next[sg] = g[x], g[x] = sg;
    c[++sg] = x, next[sg] = g[y], g[y] = sg;
}
int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    n = getint(); m = getint();
    for (int i = 1; i <= n; ++i)  col[i] = getint() + 1;
    for (int i = 1; i < n; ++i) 
      x = getint(), y = getint(), add(x, y);  
    sg = 0;
    dfs(1);  nowp = 1, mak(1, 1);  build(1, n, 1); 
    for (int i = 1; i <= m; ++i)
      {
          while (ch != 'C'  &&  ch != 'Q')  ch = getchar();
          if (ch == 'Q')  x = getint(), y = getint(), printf("%d\n", query(x, y));
          else  x = getint(), y = getint(), co = getint(), change(x, y, co + 1);
      }      
}


#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define a p[c[x][0]]
#define b p[c[x][1]]
char ch;
#define add(A, B) cp[++sg] = B, next[sg] = g[A], g[A] = sg
#define gs (ch < '0' ||  ch > '9')
int getint() { int wis = 0; ch = getchar(); while (gs) ch = getchar(); while (!gs) wis = wis * 10 + ch - '0', ch = getchar(); return wis; }
const int ys = 100010;
using namespace std;

int n, m, x, y, z, q, lap, sg;
int g[ys], next[ys * 2], cp[ys * 2];
int col[ys], pus[ys];
int c[ys][2], w[ys], f[ys];

struct Lek
{
    int tot, right, left;
}   p[100010], ans, clear;
void update(int x)
{
    p[x].tot = a.tot + b.tot - (a.right == col[x]) - (b.left == col[x]) + 1;
    p[x].left = !a.left ? col[x] : a.left;
    p[x].right = !b.right ? col[x] : b.right;
}
void push(int x)
{
    if (pus[x])  
      pus[c[x][0]] = pus[c[x][1]] = col[c[x][0]] = col[c[x][1]] = pus[x],
      p[c[x][0]] = p[c[x][1]] = (Lek){1, pus[x], pus[x]};
    pus[x] = 0;
    p[0] = clear;  pus[0] = col[0] = 0;
}
void rota(int x)
{
    int y = f[x], p, q;  push(y);  push(x);
    w[x] = w[y];  p = c[y][1] == x;  q = !p;
    if (w[y])  c[f[y]][y == c[f[y]][1]] = x;  w[y] = 1;
    f[x] = f[y];  f[y] = x;
    c[y][p] = c[x][q];  f[c[x][q]] = y; 
    c[x][q] = y;  
    update(y);   
}
void splay(int x)
{
    int y, z;   
    for (; w[x]; rota(x))
      if (y = f[x], z = f[y], w[y])
        if ((c[y][1] == x) ^ (c[z][1] == y))
          rota(y);  else  rota(x);
    push(x);  update(x);
}
int access(int u)
{
    int v = 0;
    for (; u; v = u, u = f[u])
      {   
          splay(u);  lap = c[u][1];
          if (c[u][1])  w[c[u][1]] = 0; c[u][1] = v;
          if (v)  f[v] = u, w[v] = 1;   
          update(u);
      }    
    return v;
}
void dfs(int z)
{
    for (int x = g[z]; x; x = next[x])
      if (cp[x] != f[z])  f[cp[x]] = z, dfs(cp[x]);
}
int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    n = getint(), m = getint();
    for (int i = 1; i <= n; ++i)  
      col[i] = getint() + 1, p[i] = (Lek){1, col[i], col[i]};
    for (int i = 1; i < n; ++i) 
      x = getint(), y = getint(), add(x, y), add(y, x);
    dfs(1);
    for (int i = 1; i <= m; ++i)
      {
          while (ch != 'C'  &&  ch != 'Q')  ch = getchar();
          if (ch == 'C')  
            {
               x = getint(); y = getint(); z = getint() + 1;
               access(x);  q = access(y);  splay(q);  
               pus[c[q][1]] = pus[lap] = col[c[q][1]] = col[lap] = col[q] = z;  
               p[c[q][1]] = p[lap] = (Lek){1, z, z};
               update(q);
               p[0] = clear;  pus[0] = col[0] = 0;
            }     
          else
            {
               x = getint(); y = getint();
               access(x);  q = access(y);  splay(q);
               printf("%d\n", p[lap].tot + 1 + p[c[q][1]].tot - (p[lap].left == col[q]) - (p[c[q][1]].left == col[q]));  
            }    
      }    
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值