开心~今天A了两道树链剖分的题,和一道可持久化线段树。
预备知识就不说了。
讲一下我调了快一天的(简单题。
没错,我重写了一遍软件包管理器……
[终于没有BUG了好开心……
题意大概这样:
给定一棵树,对它进行黑白染色,你可以把一条从根到某个结点的路径都染黑,也可以把某个子树都染白,起初,整棵树都是白色,每次操作回答一共有多少个点颜色发生变化。
子树操作:Modify(a,a + sz[a] - 1);
路径操作:大家都会……一个一个往上跳啊跳就可以了。
/* ID:SingleLyra PROG:NOI 2015 软件包管理器 LANG:C++ KEY:Heavy-Light Decomposition */
#include <iostream>
#include <cstdio>
#include <cstring>
#define RepG(i,x) for(int i = head[x] ; ~ i ; i = edge[i].next)
#define v edge[i].to
#define Rep(i,n) for(int i = 1; i <= n ; i ++)
#define RD(i,x,n) for(int i = x; i <= n ; i ++)
#define CLR(a,b) memset(a,b,sizeof(a))
#define N 100005
int son[N],fa[N],tid[N],dep[N],top[N],sz[N],head[N << 1],cnt = 0,tim = 0,n,op,sum[N << 2],tag[N << 2];
struct Edge{
int next,to;
}edge[N << 1];
int read(){
char ch = getchar ();
int x = 0 , flag = 1;
while(ch > '9' || ch < '0' && ch != '-')ch = getchar ();
if(ch == '-') ch = getchar (),flag = -1;
while(ch <= '9' && ch >= '0')x = 10 * x + ch - '0' ,ch = getchar ();
return x * flag ;
}
void Init(){CLR(head,-1);CLR(son,-1);CLR(tag,-1);CLR(sum,0);}
void save(int a,int b){edge[cnt].to = b,edge[cnt].next = head[a] ,head[a] = cnt ++;}
//Heavy _ Light
void dfs1(int x,int f,int depth){
dep[x] = depth;
fa[x] = f;
sz[x] = 1;
RepG(i,x)
if(v != f){
dfs1(v,x,depth + 1);
sz[x] += sz[v];
if(son[x] == -1 || sz[son[x]] < sz[v])
son[x] = v;
}
}
void dfs2(int x,int tp){
top[x] = tp;
tid[x] = ++ tim;
if(son[x] == -1)return ;
dfs2(son[x],tp);
RepG(i,x)
if(v != fa[x] && v != son[x])
dfs2(v,v);
}
//Seg
#define lson rt << 1,l,mid
#define rson rt << 1|1,mid + 1,r
void swap(int &a,int &b){int c = a ;a = b,b = c;}
void up(int x){sum[x] = sum[x << 1] + sum[x << 1 | 1];}
void down(int x,int l,int r){
int mid = l + r >> 1;
if(~tag[x]){
sum[x << 1] = tag[x] * (mid - l + 1);
sum[x << 1 | 1] = tag[x] * (r - mid);
tag[x << 1] = tag[x << 1 | 1] = tag[x];
tag[x] = -1;
}
}
void modify(int rt,int l,int r,int ml,int mr,int s){
if(l >= ml && r <= mr){
tag[rt] = s;
sum[rt] = (r - l + 1) * s;
return;
}
int mid = l + r >> 1;
down(rt,l,r);
if(mid >= ml)modify(lson,ml,mr,s);
if(mid < mr)modify(rson,ml,mr,s);
up(rt);
}
int query(int rt,int l,int r,int ql,int qr){
if(l >= ql && r <= qr)return sum[rt];
int res = 0;
down(rt,l,r);
int mid = (l + r) >> 1;
if(mid >= ql)res += query(lson,ql,qr);
if(mid < qr)res += query(rson,ql,qr);
up(rt);
return res;
}
void Modify(int a,int b){
while(top[a] != top[b]){
if(dep[top[a]] < dep[top[b]])swap(a,b);
modify(1,1,n,tid[top[a]],tid[a],1);
a = fa[top[a]];
}
if(dep[a] > dep[b])swap(a,b);
modify(1,1,n,tid[a],tid[b],1);
}
int Query(int a,int b){
int ans = 0;
while(top[a] != top[b]){
if(dep[top[a]] < dep[top[b]])swap(a,b);
ans += query(1,1,n,tid[top[a]],tid[a]);
a = fa[top[a]];
}
if(dep[a] > dep[b])swap(a,b);
ans += query(1,1,n,tid[a],tid[b]);
return ans;
}
int main (){
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
Init();
n = read();
RD(i,2,n){
int a = read();
a ++;
save(a,i),save(i,a);
}
dfs1(1,0,1);
dfs2(1,1);
op = read();
do{
char step[15];
int p;
scanf("%s",step);
p = read();
++ p;
if(step[0] == 'i'){
int res = Query(1,p);
Modify(1,p);
int res2 = dep[p];
printf("%d\n",res2 - res);
}
else {
int res = query(1,1,n,tid[p],tid[p] + sz[p] - 1);
modify(1,1,n,tid[p],tid[p] + sz[p] - 1,0);
printf("%d\n",res);
}
}while(-- op);
return 0;
}
下一题是SPOJ375。题意是这样的:
给定一棵树,每个边都有边权。
有两种操作:
1.修改某条边的值。
2.询问某条路径上的最大值。
简单来分析的话,似乎直接树链剖分就可以解了?
然而……
这里并不是点权啊喂!看清楚题意啊同学!
考虑一个(**做法:)拆点:
a——b连着一条边权为w的边。
则:a——c,c——b;把w赋到c上,简称wc。(其他两个点点权为0)
好的我们已经这样做好了,对新树进行树链剖分,除了空间浪费太大以外并没有什么问题2333
然而!
Modify的时候?
Modify(a,b,d):把a——b的边权改成d。
于是我就傻乎乎地改了三个点的点权……
其实特判一下还是可以做的……可你不觉得很蠢么……
正确解法:
不要那么局限啦……
可以考虑对边建立线段树的……
记录tid[x]为:fa[x]与x的连边在线段树所在的位置。
“那根节点怎么办?”
只有一个根吧……
而且根的时间戳必然是1。
(证明:dfs是不是从根开始!!!)
所以我们可以大方的建立一个[2,n]的线段树。
至于那个1节点……没什么用……
总之看代码就好了……
#include <cstdio>
#include <cstring>
#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)
#define Rep(i,n) for(int i = 1 ; i <= n ; i ++)
#define N 210000
#define v edge[i].to
#define CLR(a,b) memset(a,b,sizeof(a))
struct Edge{
int next,to;
}edge[N << 1];
const int _inf = 1 << 31;
int Max[N << 2],E[N][3],son[N],f[N],dep[N],sz[N],head[N << 1],tid[N],tim = 0,cnt = 0,top[N];
int n ;
void Init(){
CLR(head,-1);CLR(son,-1);CLR(Max,-127);tim = cnt = 0;
}
void dfs1(int x,int fa,int depth){
sz[x] = 1;
dep[x] = depth;
f[x] = fa;
RepG(i,x)
if(v != fa){
dfs1(v,x,depth + 1);
sz[x] += sz[v];
if(son[x] == -1 || sz[son[x]] < sz[v])
son[x] = v;
}
}
void dfs2(int x,int tp){
tid[x] = ++ tim;
top[x] = tp;
if(son[x] == -1)return;
dfs2(son[x] , tp);
RepG(i,x)
if(v != f[x] && v != son[x])
dfs2(v,v);
}
void save(int a,int b){
edge[cnt].next = head[a];
edge[cnt].to = b;
head[a] = cnt ++;
}
#define lson x << 1,l,mid
#define rson x << 1 | 1,mid + 1,r
int max(int a,int b){return a > b ? a : b;}
void swap(int &a,int &b){int c = a;a = b,b = c;}
void up(int x){Max[x] = max(Max[x << 1] ,Max[x << 1 | 1]);}
int query(int x,int l,int r,int ql,int qr){
if(l >= ql && r <= qr)return Max[x];
if(l > qr || r < ql)return _inf;
int mid = l + r >> 1;
int ans = _inf;
if(ql <= mid)ans = max(ans,query(lson,ql,qr));
if(qr > mid)ans = max(ans,query(rson,ql,qr));
return ans;
}
int Query(int a,int b){
int ans = _inf;
while(top[a] != top[b]){
if(dep[top[a]] < dep[top[b]])swap(a,b);
ans = max(ans,query(1,2,n,tid[top[a]],tid[a]));
a = f[top[a]];
}
if(dep[a] < dep[b])swap(a,b);
ans = max(ans,query(1,2,n,tid[b] + 1,tid[a]));//略微注意一下:这里是tid[b] + 1的原因是:我们只询问b到a单条链的信息,所以不包含b的父亲。
return ans ;
}
void Modify(int x,int l,int r,int s,int Mo){
if(l == r && l == s){
Max[x] = Mo;
return;
}
int mid = l + r >> 1;
if(s <= mid)Modify(lson,s,Mo);
else Modify(rson,s,Mo);
up(x);
}
int main (){
int Case;
scanf("%d",&Case);
while(Case --){
Init();
scanf("%d",&n);
for(int i = 1; i < n ; i ++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
save(a,b),save(b,a);
E[i][0] = a,E[i][1] = b,E[i][2] = c;
}
dfs1(1,0,1);
dfs2(1,1);
char s[15];
Rep(i,n - 1){
if(dep[E[i][0]] < dep[E[i][1]])
swap(E[i][0],E[i][1]);
Modify(1,2,n,tid[E[i][0]],E[i][2]);
}
while(scanf("%s",s + 1),s[1] != 'D'){
int a,b;
scanf("%d%d",&a,&b);
if(s[1] == 'Q')
printf("%d\n",Query(a,b));
else
Modify(1,2,n,tid[E[a][0]],b);
}
puts("");
}
return 0;
}
接下来会写一写道馆之战……