【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)
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
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
1
2
2
10
6
5
6
5
16
HINT
Source
【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)的更多相关文章
- Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)
Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...
- bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 10677 Solved: 4313[Submit ...
- bzoj 1036: [ZJOI2008]树的统计Count (树链剖分+线段树 点权)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 21194 Solved: 8589[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)
树的统计CountDescription一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改 ...
- 1036: [ZJOI2008]树的统计Count (树链剖分)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3401 Solved: 1418[Submit] ...
- 1036: [ZJOI2008]树的统计Count(树链剖分)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 19830 Solved: 8067[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分+单点更新+区间求和+区间求最大值)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:略. 题解:树链剖分模版,注意一些细节即可. #include <ios ...
- BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
- BZOJ 1036:树的统计Count(树链剖分)
http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:中文题意. 思路:也是普通的树链剖分.唯一注意的点是在change函数中 while(t ...
- 【BZOJ1036】树的统计Count(树链剖分,LCT)
题意:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: ...
随机推荐
- 在Shell里面判断字符串是否为空
在Shell里面判断字符串是否为空 分类: Linux shell2011-12-28 23:18 15371人阅读 评论(0) 收藏 举报 shell 主要有以下几种方法: echo “$str” ...
- 查看一些特定sql需求的书写
user表,5个人abcde, content表10篇文章,一个人对应两篇文章,有 time字段,查询出五个人的最新文章. select a.id,a.SName,a.ClsNo,a.Scorefr ...
- ios7技巧:你需要掌握的19个iOS7使用技巧
从右往左滑动屏幕,可看到信息收到的时间. 指南针应用还可以用作水平仪,滑动屏幕即可. 被苹果称作Spotlight的搜索功能有所改变.在屏幕中间向下滑动即可打开该项功能,你可以搜索文本.邮件.应用.歌 ...
- Two Sum I & II
Two Sum I Given an array of integers, find two numbers such that they add up to a specific target nu ...
- 通过关闭UseDNS和GSSAPIAuthentication选项加速SSH登录
引自:http://www.cnblogs.com/wjoyxt/p/3790537.html More:http://blogread.cn/it/article/4719 通常情况下我们在连接 O ...
- 26.打印所有和为S的连续正整数序列[FindContinuousSequencesWithSumS]
[题目] 输入一个正数n,输出所有和为n连续正数序列.例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5.4-6和7-8. [分析] 这是网易的一道面试题.这道 ...
- Cocos2d 中的Sprite大小调整问题
以前用UIImageView,比如 UIImageView *view = [[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"b ...
- Android 中的Resource
Android与ios相比,各种各样Resource算个独特之处.详情请参见官网Resource Types Resource有许多种,常见的有图像资源,布局资源,等等.每一种资源的位置都是固定的,这 ...
- DisJSet:食物链(POJ 1182)
动物王国的食物链 这一题有两种思路,先介绍第一种: 题目是中文的,我就不翻译了,也很好理解,就是一个A-B-C-A的一个循环的食物链,给定一些条件,问你哪些条件是错的 这一题,是一道比较 ...
- 设置IIS会话过期时间
打开默认网站----双击ASP--展开会话属性---更改超时时间-