http://www.lydsy.com/JudgeOnline/problem.php?id=1036

lct:

(ps:为嘛我的那么慢T_T,不知道排到哪了。。难道别人都是树剖吗。。。看来有必要学 orz

裸的lct,这里只说一下找路径就行了。,。算了,上晚修去了,待会回来更

lca大家应该都会求,就是2次access就行了(很容易理解的)

然后我们求路径的时候,用lca的右子女的值和lca自身的值和第一次access的点的值来更新就行了,

但是这里有特殊情况,就是lca==第一次access的点的情况,因为这是第一个点是第二个点的父亲,那么直接用lca的值就能更新,再用第一个点的值来更新就重复了。

(为什么lca==第二次access的点不需要判呢。。自己想把。很简单)

#include <cstdio>
#include <iostream>
using namespace std;
#define dbg(x) cout << #x << "=" << x << endl
#define read(x) x=getint()
#define print(x) printf("%d", x)
#define max(a,b) ((a)>(b)?(a):(b)) const int oo=~0u>>1;
inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; }
const int N=30010, M=100005;
int ihead[N], inext[M], to[M], cnt, q[N], front, tail, n, m;
bool vis[N]; struct node* null;
struct node {
node* fa, *ch[2];
int w, sum, mx;
bool d() { return fa->ch[1]==this; }
bool check() { return fa->ch[0]!=this && fa->ch[1]!=this; }
void setc(node* c, bool d) { ch[d]=c; c->fa=this; }
void pushup() {
sum=w+ch[0]->sum+ch[1]->sum;
mx=max(w, max(ch[0]->mx, ch[1]->mx));
}
}*nd[N]; inline void rot(node* r) {
node* fa=r->fa; bool d=r->d();
if(fa->check()) r->fa=fa->fa;
else fa->fa->setc(r, fa->d());
fa->setc(r->ch[!d], d);
r->setc(fa, !d);
fa->pushup();
} inline void splay(node* r) {
while(!r->check())
if(r->fa->check()) rot(r);
else r->d()==r->fa->d()?(rot(r->fa), rot(r)):(rot(r), rot(r));
r->pushup();
} inline node* access(node* fa) {
node* c=null;
for(; fa!=null; c=fa, fa=fa->fa) {
splay(fa);
fa->setc(c, 1);
fa->pushup();
}
return c;
} inline void bfs() {
vis[1]=1; int u, v, i;
front=tail=0; q[tail++]=1;
while(front!=tail) {
u=q[front++];
for(i=ihead[u]; i; i=inext[i]) if(!vis[v=to[i]]) {
vis[v]=1;
nd[v]->fa=nd[u];
q[tail++]=v;
}
}
} inline void add(const int &u, const int &v) {
inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
} int main() {
null=new node; null->fa=null->ch[0]=null->ch[1]=null; null->w=null->sum=0; null->mx=oo+1;
read(n);
int u, v, t;
for(int i=1; i<n; ++i) {
read(u); read(v);
add(u, v);
}
int w;
for(int i=1; i<=n; ++i) {
nd[i]=new node;
read(w);
nd[i]->w=w;
nd[i]->ch[0]=nd[i]->ch[1]=nd[i]->fa=null;
}
bfs();
char c[10];
node* lca=null;
read(m);
int ans;
for(int i=0; i<m; ++i) {
scanf("%s", c);
if(c[0]=='C') {
read(u); read(t);
splay(nd[u]);
nd[u]->w=t;
nd[u]->pushup();
}
else if(c[0]=='Q') {
read(u); read(v);
access(nd[u]);
lca=access(nd[v]);
splay(nd[u]);
if(nd[u]==lca) {
if(c[1]=='M') ans=max(lca->w, lca->ch[1]->mx);
else ans=lca->w + lca->ch[1]->sum;
}
else {
if(c[1]=='M') ans=max(max(lca->w, nd[u]->mx), lca->ch[1]->mx);
else ans=lca->w + lca->ch[1]->sum + nd[u]->sum;
}
printf("%d\n", ans);
}
}
return 0;
}

树链剖分,裸模板题:

好慢啊

#include <cstdio>
#include <iostream>
using namespace std;
#define dbg(x) cout << #x << "=" << x << endl
#define read(x) x=getint()
#define print(x) printf("%d", x)
#define lc x<<1
#define rc x<<1|1
#define lson l, m, lc
#define rson m+1, r, rc
#define MID (l+r)>>1 const int oo=~0u>>1;
inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; } const int N=30010, M=100005;
int ihead[N], inext[M], to[M], cnt, n, m;
int top[N], son[N], fa[N], dep[N], sz[N], id[N], a[N], b[N], tot;
int L, R, key; struct node { int mx, sum; }t[N*50];
inline const int max(const int& a, const int& b) { return a>b?a:b; }
inline void pushup(const int &x) { t[x].mx=max(t[lc].mx, t[rc].mx); t[x].sum=t[lc].sum+t[rc].sum; } void dfs1(const int &u) {
sz[u]=1; int v;
for(int i=ihead[u]; i; i=inext[i]) if(fa[u]!=(v=to[i])) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
} void dfs2(const int &u, const int &tp) {
id[u]=++tot; top[u]=tp; b[tot]=a[u];
if(son[u]) dfs2(son[u], tp);
for(int i=ihead[u]; i; i=inext[i]) if(to[i]!=fa[u] && to[i]!=son[u]) dfs2(to[i], to[i]);
} void build(const int &l, const int &r, const int &x) {
if(l==r) { t[x].mx=t[x].sum=b[l]; return; }
int m=MID;
build(lson); build(rson);
pushup(x);
} void update(const int &l, const int &r, const int &x) {
if(l==r) { t[x].mx=t[x].sum=key; return; }
int m=MID;
if(L<=m) update(lson);
if(m<R) update(rson);
pushup(x);
} int getmax(const int &l, const int &r, const int &x) {
if(L<=l && r<=R) return t[x].mx;
int m=MID, mx=oo+1;
if(L<=m) mx=max(mx, getmax(lson));
if(m<R) mx=max(mx, getmax(rson));
return mx;
} int query(const int &l, const int &r, const int &x) {
if(L<=l && r<=R) return t[x].sum;
int m=MID, ret=0;
if(L<=m) ret+=query(lson);
if(m<R) ret+=query(rson);
return ret;
} inline int getmax(int x, int y) {
int fx=top[x], fy=top[y], ret=oo+1;
while(fx!=fy) {
if(dep[fx]<dep[fy]) { swap(x, y); swap(fx, fy); }
L=id[fx], R=id[x];
ret=max(ret, getmax(1, n, 1));
x=fa[fx]; fx=top[x];
}
if(dep[x]>dep[y]) swap(x, y);
L=id[x], R=id[y];
return max(ret, getmax(1, n, 1));
} inline int query(int x, int y) {
int fx=top[x], fy=top[y], ret=0;
while(fx!=fy) {
if(dep[fx]<dep[fy]) { swap(x, y); swap(fx, fy); }
L=id[fx], R=id[x];
ret+=query(1, n, 1);
x=fa[fx]; fx=top[x];
}
if(dep[x]>dep[y]) swap(x, y);
L=id[x], R=id[y];
return ret+query(1, n, 1);
} inline void add(const int &u, const int &v) {
inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
} int main() {
read(n);
int u, v, ans;
for(int i=1; i<n; ++i) {
read(u); read(v);
add(u, v);
}
for(int i=1; i<=n; ++i) read(a[i]);
dfs1(1);
dfs2(1, 1);
build(1, n, 1);
char c[10];
read(m);
for(int i=0; i<m; ++i) {
scanf("%s", c);
if(c[0]=='C') {
read(u); read(key); L=R=id[u];
update(1, n, 1);
}
else if(c[0]=='Q') {
read(u); read(v);
if(c[1]=='M') ans=getmax(u, v);
else ans=query(u, v);
printf("%d\n", ans);
}
}
return 0;
}

Description

一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

输 入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数 q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到 30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

HINT

Source

【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)的更多相关文章

  1. Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)

    Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...

  2. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  3. bzoj 1036: [ZJOI2008]树的统计Count (树链剖分+线段树 点权)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 21194  Solved: 8589[Submit ...

  4. BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)

    树的统计CountDescription一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改 ...

  5. 1036: [ZJOI2008]树的统计Count (树链剖分)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3401  Solved: 1418[Submit] ...

  6. 1036: [ZJOI2008]树的统计Count(树链剖分)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 19830  Solved: 8067[Submit ...

  7. BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分+单点更新+区间求和+区间求最大值)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:略. 题解:树链剖分模版,注意一些细节即可. #include <ios ...

  8. BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】

    Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...

  9. BZOJ 1036:树的统计Count(树链剖分)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:中文题意. 思路:也是普通的树链剖分.唯一注意的点是在change函数中 while(t ...

  10. 【BZOJ1036】树的统计Count(树链剖分,LCT)

    题意:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: ...

随机推荐

  1. 【OpenStack】OpenStack系列1之OpenStack本地开发环境搭建&&向社区贡献代码

    加入OpenStack社区 https://launchpad.net/,注册用户(597092663@qq.com/Admin@123) 修改个人信息,配置SSH keys.OpenPGP keys ...

  2. Rehashing

    The size of the hash table is not determinate at the very beginning. If the total size of keys is to ...

  3. Intersection of Two Arrays | & ||

    Intersection of Two Arrays Given two arrays, write a function to compute their intersection. Example ...

  4. Object-c 控制语句

    控制语句: 分支语句   if-else  有控制机制    switch 循环语句   while    do-while  for 跳转语句   break,continue,goto

  5. lambda 表达式

    C++0x 的语法还是比较简单.下面通过几个例子来介绍下. 先是通过 std::for_each 演示一个简单的例子: ? std::for_each 和 lambda 1 2 3 4 5 6 7 8 ...

  6. 1.2 中国象棋将帅问题进一步讨论与扩展:如何用1个变量实现N重循环?[chinese chess]

    [题目] 假设在中国象棋中只剩下将帅两个棋子,国人都知道基本规则:将帅不能出九宫格,只能上下左右移动,不能斜向移动,同时将帅不能照面.问在这样条件下,所有可能将帅位置.要求在代码中只能使用一个字节存储 ...

  7. mybatis前台传给带年月日时分秒的数据给后台,后台接收不到时分秒

    框架spring+springMVC+mybatis, 前台给后台传数据传不了时分秒,所以用springMVC的注解解决了,记录一下 controller中如下: /** * * 方法描述 : 使用@ ...

  8. Myeclipse中把java代码导成UML类图

    Myeclipse中把java代码导成UML类图 1.右键点击项目名称,选择New-------àUML2 Model 2.给类图命名 3.导成类图 1)如果要把整个项目导成类图,则把整个项目拖到类图 ...

  9. PW试验-----verilog

    PWM,脉冲宽度调制.顾名思义,是通过调制脉冲的宽度,即占空比,来实现的.可是使占空比逐渐由最小增加到最大,也可以使占空比由最大减少到最小来实现不同的现象.若用LED灯来显示现象,则可以称作:LED呼 ...

  10. css局部概念的理解:

    1.DIV-Padding理解:一直以来对div中的padding属性,一直不理解,使用最多的也就是margin,padding是div的内空间的相对距离,margin是div的外部相对位置,如果用一 ...