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. yum 配置

    1.配置yum本地源 # mount /dev/cdrom /mnt/ # vim /etc/yum.repos.d/rhel-source.repo 1 [rhel-source] 2 name=R ...

  2. python 中接口的实现

    实际上,由于python是动态语言,支持多继承,因此接口在语言层面,是没有的东东. 然后,在架构设计上,我们又需要这么一个东西,来规范开发人员的行为. 因此就有了zope.interface的诞生. ...

  3. Ubuntu 更改文件夹权限及chmod详细用法

    转自: http://blog.chinaunix.net/uid-21880738-id-1813031.html 对Document/目录下的所有子文件与子目录执行相同的权限变更: Documen ...

  4. 3Sum Closest & 3Sum Smaller

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  5. cocos2d c++ 代码规范(译文)

    原文在http://cocos2d-x.org/projects/cocos2d-x/wiki/Cocos2d_c++_coding_style,我觉得这个规范非常全面,写的非常好,我只捡一些我认为比 ...

  6. swift 中String,Int 等类型使用注意,整理中

    swfit中的String和Int是 struct定义的,不同于NSString和NSNumber, 如果想在一个数组中同时包含String和Int,那么这个数组要声明为[Any] 而不是 [AnyO ...

  7. iOS constraint被应用于view上的时间

    在viewdidload时,constraint是没有被应用的,之后在layoutSubviews时,系统应用了constraint.但是我感觉在viewWillLayoutSubviews函数时就已 ...

  8. 不使用arc功能时的编译参数 –fno-objc-arc

    用一些老代码时,里面总有release调用,你需要用上这个标记,不使用arc功能编译代码.我总记不住具体写法,做个记录.

  9. Java for LeetCode 063 Unique Paths II

    Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...

  10. July 19th, Week 30th Tuesday, 2016

    The good seaman is known in bad weather. 惊涛骇浪,方显英雄本色. You can't be afraid to fail. It's the only way ...