Tsinsen A1303. tree(伍一鸣) LCT

LCT的各种操作。。。。

cut link add mul size rev query

写的效率不够高。。。BZOJ上似乎TLE。。。。

A1303. tree(伍一鸣)

时间限制:2.5s   内存限制:64.0MB

总提交次数:727   AC次数:238  
平均分:45.59

将本题分享到:

查看未格式化的试题   提交   试题讨论

试题来源

  2012中国国家集训队命题答辩

问题描述

  一棵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行,每行描述一个操作

输出格式

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

样例输入

3 2

1 2

2 3

* 1 3 4

/ 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

提交   试题讨论

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long int LL;
const int maxn=100100;
const LL mod=51061;
int ch[maxn][2],pre[maxn];
bool rev[maxn],rt[maxn];
LL size[maxn],key[maxn],add[maxn],mul[maxn],sum[maxn];
void update_add(int r,LL d)
{
  if(!r) return ;
  if(d==0) return ;
  key[r]=(key[r]+d)%mod;
  add[r]=(add[r]+d)%mod;
  sum[r]=(size[r]*d+sum[r])%mod;
}
void update_mul(int r,LL d)
{
  if(!r) return ;
  if(d==1) return ;
  sum[r]=(sum[r]*d)%mod;
  key[r]=(key[r]*d)%mod;
  mul[r]=(mul[r]*d)%mod;
  add[r]=(add[r]*d)%mod;
}
void update_rev(int r)
{
  if(!r) return ;
  swap(ch[r][0],ch[r][1]);
  rev[r]=rev[r]^1;
}
void push_down(int r)
{
  if(!r) return ;
  if(rev[r])
    {
      if(ch[r][0]) update_rev(ch[r][0]);
      if(ch[r][1]) update_rev(ch[r][1]);
      rev[r]=0;
    }
  if(mul[r]!=1)
    {
      if(ch[r][0]) update_mul(ch[r][0],mul[r]);
      if(ch[r][1]) update_mul(ch[r][1],mul[r]);
      mul[r]=1;
    }
  if(add[r])
    {
      if(ch[r][0]) update_add(ch[r][0],add[r]);
      if(ch[r][1]) update_add(ch[r][1],add[r]);
      add[r]=0;
    }
 }
void push_up(int r)
{
  sum[r]=key[r]%mod;
  size[r]=1;
  if(ch[r][0])
    {
      sum[r]=(sum[r]+sum[ch[r][0]])%mod;
      size[r]+=size[ch[r][0]];
    }
  if(ch[r][1])
    {
      sum[r]=(sum[r]+sum[ch[r][1]])%mod;
      size[r]+=size[ch[r][1]];
    }
}
void Rotate(int x)
{
  int y=pre[x],kind=ch[y][1]==x;
  ch[y][kind]=ch[x][!kind];
  pre[ch[y][kind]]=y;
  pre[x]=pre[y];
  pre[y]=x;
  ch[x][!kind]=y;
  if(rt[y]) rt[y]=false,rt[x]=true;
  else ch[pre[x]][ch[pre[x]][1]==y]=x;
  push_up(y);
}
void P(int r)
{
  if(!rt[r]) P(pre[r]);
  push_down(r);
}
void Splay(int r)
{
  P(r);
  while(!rt[r])
    {
      int f=pre[r],ff=pre[f];
      if(rt[f]) Rotate(r);
      else if((ch[ff][1]==f)==(ch[f][1]==r)) Rotate(f),Rotate(r);
      else Rotate(r),Rotate(r);
    }
  push_up(r);
}
int Access(int x)
{
  int y=0;
  for(;x;x=pre[y=x])
    {
      Splay(x);
      rt[ch[x][1]]=true; rt[ch[x][1]=y]=false;
      push_up(x);
    }
  return y;
}
void mroot(int r)
{
  Access(r);
  Splay(r);
  update_rev(r);
}
void link(int u,int v)
{
  mroot(u);
  pre[u]=v;
}
void cut(int u,int v)
{
  mroot(u);
  Splay(v);
  pre[ch[v][0]]=pre[v];
  pre[v]=0;
  rt[ch[v][0]]=true;
  ch[v][0]=0;
  push_up(v);
}
void Add(int u,int v,LL d)
{
  mroot(u);
  Access(v);
  Splay(v);
  update_add(v,d);
}
void Mul(int u,int v,LL d)
{
  mroot(u);
  Access(v);
  Splay(v);
  update_mul(v,d);
}
void debug();
void query(int u,int v)
{
  mroot(u);
  Access(v);
  Splay(v);
  //cout<<"size: "<<size[v]<<" sum: "<<sum[v]<<endl;
  printf("%lld\n",sum[v]);
}
struct Edge
{
  int to,next;
}edge[maxn*2];
int Adj[maxn],Size;

void add_edge(int u,int v)
{
  edge[Size].to=v; edge[Size].next=Adj[u]; Adj[u]=Size++;
}
int n,q;
void init()
{
  Size=0;
  for(int i=0;i<=n+10;i++)
    {
      Adj[i]=-1;
      ch[i][0]=ch[i][1]=0;
      pre[i]=0; rt[i]=true; rev[i]=false;
      key[i]=1; size[i]=1; add[i]=0; mul[i]=1; sum[i]=1;
    }
}
void dfs(int u)
{
  for(int i=Adj[u];~i;i=edge[i].next)
    {
      int v=edge[i].to;
      if(pre[v]!=0) continue;
      pre[v]=u;
      dfs(v);
    }
}
void showit(int x)
{
    if(x)
    {
        push_down(x);
        showit(ch[x][0]);
        printf("结点: %2d 左儿子: %2d 右儿子: %2d 父结点: %2d size: %2lld sum: %2lld key: %2lld\n",
               x,ch[x][0],ch[x][1],pre[x],size[x],sum[x],key[x]);
        showit(ch[x][1]);
    }
}
void debug()
{
  for(int i=0;i<=n;i++)
    {
      if(rt[i])
        {
          cout<<"ROOT: "<<i<<endl;
          showit(i);
          cout<<"..........\n";
        }
    }
}
int main()
{
  while(scanf("%d%d",&n,&q)!=EOF)
    {
      init();
      for(int i=0;i<n-1;i++)
        {
          int u,v;
          scanf("%d%d",&u,&v);
          add_edge(u,v); add_edge(v,u);
        }
      pre[1]=-1; dfs(1); pre[1]=0;
      //debug();
      char op[10];
      while(q--)
        {
          scanf("%s",op);
          if(op[0]=='+')
            {
              int u,v,c;
              scanf("%d%d%d",&u,&v,&c);
              Add(u,v,c);
            }
          else if(op[0]=='-')
            {
              int u1,v1,u2,v2;
              scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
              cut(u1,v1);
              link(u2,v2);
            }
          else if(op[0]=='*')
            {
              int u,v,c;
              scanf("%d%d%d",&u,&v,&c);
              Mul(u,v,c);
            }
          else if(op[0]=='/')
            {
              int u,v;
              scanf("%d%d",&u,&v);
              query(u,v);
            }
          //debug();
        }
    }
  return 0;
}
时间: 2024-12-17 11:54:59

Tsinsen A1303. tree(伍一鸣) LCT的相关文章

[COGS 1799][国家集训队2012]tree(伍一鸣)

Description 一棵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的余数. Input 第一行两个整数n,q 接下来n-1行每行两个正整数u,v,

【国家集训队2012】tree(伍一鸣)

题面 传送门 Sol 这不是一道LCT模板题吗? 和线段树一样维护区间加法和乘法标记 记得要更新自己本身的权值 这种题就该一遍AC # include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) # define Sqr(x) ((x) * (x)) # define ls ch[0][x] # define rs ch[1][x] usi

BZOJ2631 tree(伍一鸣) LCT 秘制标记

这个题一看就是裸地LCT嘛,但是我wa了好几遍,这秘制标记...... 注意事项:I.*对+有贡献 II.先下传*再下传+(因为我们已经维护了+,不能再让*对+产生贡献)III.维护+用到size #include<cstdio> #include<cstring> #include<iostream> #define MAXN 100005 #define P 51061 using namespace std; inline unsigned int read()

HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)

Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node is associated with an integer as the weight. Your task is to deal with M operations of 4 types: 1.Delete an edge (x, y) from the tree, and then add a

【刷题】洛谷 P1501 [国家集训队]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,

王学长的AAA树

让我们响应王学长的号召勇敢的分开写splay和lct吧! 分开写大法好!!!!!!!!!!!杜教的ch[4]弱爆了!!!! 1 #include <stdio.h> 2 #include <algorithm> 3 char ch; 4 inline void read(int &x) 5 { 6 x=0;ch=getchar(); 7 while(ch<=32) ch=getchar(); 8 while(ch>32) x=x*10+ch-48,ch=getc

【BZOJ】2049 [Sdoi2008]Cave 洞穴勘测

[算法]Link-Cut Tree [题解]lct 不是很懂你们会压常数的>_<! #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=10010; int f[maxn],t[maxn][2],n,m; bool g[maxn]; bool isroot(int x) {return (t[f[x]][0]!=x&&am

【LCT】一步步地解释Link-cut Tree

简介 Link-cut Tree,简称LCT. 干什么的?它是树链剖分的升级版,可以看做是动态的树剖. 树剖专攻静态树问题:LCT专攻动态树问题,因为此时的树剖面对动态树问题已经无能为力了(动态树问题通常夹杂着树的操作,如删边与连边.这是线段树无法应对的). LCT难写吗?不难写啊!真的没有200行...... 让我们用简洁的写法来搞定LCT:只需要一些基础函数,再疯狂调用这些函数就好啦. 1. LCT概念 树链剖分把树分成若干条重链,对于每条重链,用线段树来维护信息.利用各线段树的信息来得到答

BZOJ 2631: tree( LCT )

LCT...略麻烦... -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define