2019年ccpc女生赛重现赛题解D
题目:
Tree
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0
Problem Description
wls 有三棵树,树上每个节点都有一个值 ai,现在有 2 种操作:
- 将一条链上的所有节点的值开根号向下取整;
- 求一条链上值的和;
链的定义是两点之间的最短路。
Input
第一行两个数 n, q 分别代表树上点的数量和操作数量。
第二行 n 个整数,第 i 个数代表第 i 个点的值 ai。
接下来 n − 1 行, 每行两个整数 u, v 代表 u,v 之间有一条边。数据保证点两两联通。
接下来 q 行,每行有个整数 op, u, v,op = 0 表示将 u, v 这条链上所有的点的值开根号向下取整,op = 1表示询问 u,v 这条链上的值的和。
1 ≤ n, q ≤ 100, 000
0 ≤ ai ≤ 1, 000, 000, 000
Output
对于每一组 op = 2 的询问,输出一行一个值表示答案。
Sample Input
4 4
2 3 4 5
1 2
2 3
2 4
0 3 4
0 1 3
1 2 3
1 1 4
Sample Output
2
4
思路:树链剖分的裸题好像,也是学长敲的。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<cctype>
#include<set>
#include<stack>
#include<map>
#include<queue>
#include<vector>
#include<algorithm>
#define fi first
#define se second
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define root 1,n,1
#define PB push_back
#define MP make_pair
#define pi 3.1415926535898
#define MS(x,y) memset(x,y,sizeof(x))
#define lowbit(a) (a&(-a))
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL,LL> P;
const int maxn = 1e5 + 10,modd = 1e9 + 7,inf = 0x3f3f3f3f,INF = 0x7fffffff,hmod1=0x48E2DCE7,hmod2=0x60000005;
const int dir[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
const double eps = 1e-8;
template <class T> inline void scand(T &x){char c;x=0;while((c=getchar())<'0');while(c>='0'&&c<='9')x=x*10+(c-48),c=getchar();}
inline LL min(LL a,LL b){return a < b ? a : b;}
inline LL max(LL a,LL b){return a > b ? a : b;}
inline LL gcd(LL a,LL b){ return b==0? a: gcd(b,a%b); }
inline LL exgcd(LL a,LL b,LL &x,LL &y){ LL d; (b==0? (x=1,y=0,d=a): (d=exgcd(b,a%b,y,x),y-=a/b*x)); return d; }
inline LL qpow(LL a,LL n){LL sum=1;while(n){if(n&1)sum=sum*a%modd;a=a*a%modd;n>>=1;}return sum;}
inline LL qmul(LL a,LL n){LL sum=0;while(n){if(n&1)sum=(sum+a)%modd;a=(a+a)%modd;n>>=1;}return sum;}
inline LL inv(LL a) {return qpow(a,modd-2);}
inline LL madd(LL a,LL b){return (a%modd+b%modd)%modd;}
inline LL mmul(LL a,LL b){return a%modd * b%modd;}
inline void uadd(LL &a,LL b){a = madd(a,b);}
inline void umul(LL &a,LL b){a = mmul(a,b);}
struct Edge{int to,next;}edge[2*maxn];
LL n,m,e,tme,v[maxn],head[maxn],dep[maxn],sz[maxn],son[maxn],f[maxn],top[maxn],dfn[maxn],in[maxn];
LL lazy[4*maxn],summ[4*maxn],maxx[4*maxn];
void add_edge(int u,int v)
{
edge[++e].to = v;
edge[e].next = head[u];
head[u] = e;
}
void push_up(int rt)
{
summ[rt] = summ[rt<<1] + summ[rt<<1|1];
maxx[rt] = max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l == r)
{
summ[rt] = maxx[rt] = dfn[l];
return;
}
int m = (l + r) >> 1;
build(ls);
build(rs);
push_up(rt);
}
void update(int L,int R,int l,int r,int rt)
{
if(maxx[rt] <= 1) return;
if(l == r)
{
maxx[rt] = sqrt(maxx[rt]);
summ[rt] = sqrt(summ[rt]);
return;
}
int m = (l + r) >> 1;
if(L <= m && maxx[rt<<1] > 1) update(L,R,ls);
if(R > m && maxx[rt<<1|1] > 1) update(L,R,rs);
push_up(rt);
}
LL query_summ(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
return summ[rt];
int m = (l + r) >> 1;
LL ans = 0;
if(L <= m) ans += query_summ(L,R,ls);
if(R > m) ans += query_summ(L,R,rs);
return ans;
}
void dfs1(int u,int fa)
{
f[u] = fa,sz[u] = 1;
LL maxx = -1;
for(int i=head[u];i;i=edge[i].next)
{
int v = edge[i].to;
if(v == fa) continue;
dep[v] = dep[u] + 1;
dfs1(v,u);
sz[u] += sz[v];
if(sz[v] > maxx) son[u] = v,maxx = sz[v];
}
}
void dfs2(int u,int tp)
{
in[u] = ++tme;
dfn[tme] = v[u];
top[u] = tp; //记录重链顶端
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i;i=edge[i].next)
{
int v = edge[i].to;
if(v == f[u] || v == son[u]) continue;
dfs2(v,v); //轻链顶端是自己
}
}
void uLink(int x,int y) //查询链x --> y
{
//cout << x << ' ' << y << endl;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x,y); //优先处理重链较深的
update(in[top[x]],in[x],root);
x = f[top[x]]; //处理完一条重链,跳到上一条
}
if(dep[x] > dep[y]) swap(x,y);
update(in[x],in[y],root);
}
LL qLink(int x,int y) //查询链x --> y
{
LL ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x,y); //优先处理重链较深的
ans += query_summ(in[top[x]],in[x],root);
x = f[top[x]]; //处理完一条重链,跳到上一条
}
if(dep[x] > dep[y]) swap(x,y);
ans += query_summ(in[x],in[y],root);
return ans;
}
int main()
{
int a,b,c;
scand(n),scand(m);
for(int i=1;i<=n;i++) scand(v[i]);
for(int i=0;i<n-1;i++)
{
scand(a),scand(b);
add_edge(a,b);
add_edge(b,a);
}
dfs1(1,-1);dfs2(1,1);
build(root);
while(m--)
{
scand(a),scand(b),scand(c);
if(a == 0) uLink(b,c);
else if(a == 1) printf("%I64d\n",qLink(b,c));
}
}