「BZOJ3083」遥远的国度(树剖换根
3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 4859 Solved: 1372
[Submit][Status][Discuss]
Description
描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1
p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数
id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
HINT
Source
zhonghaoxi提供
题解
我也是有B站账号的女人了!
这道题除了换根以外就很板子了,——所以我们聊聊换根。
首先在原根下建出一棵树,设当前的根为root。
对于子树k的操作:
1.root==k 那么对整棵树操作。
2.lca(root,k)!=k 也就是说root对k并没有什么影响,直接操作k。
3.lca(root,k)==k root在k的子树中,想象一下揪着一根毛拿起一顶假发......
那么对整个树中,除了原根意义下 k的儿子中含root的那一股 以外,的整棵树操作。
(也可以认为对整个树操作,然后对root那一股撤销操作
其实,所谓的换根操作,并不是要你每次把树再重新建一遍(复杂度起飞
而是考你分类讨论的能力QAQ
——
然后,一定一定要注意边界啊!字母不要混用啊!QAQ
以及 鉴于数据极接近maxint,不如直接longlong2333
/**************************************************************
Problem: 3083
User: qwerta
Language: C++
Result: Accepted
Time:5528 ms
Memory:55532 kb
****************************************************************/ #include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define R register
const int MAXN=;
struct emm{
int e,f;
}b[*MAXN];
int h[MAXN];
int tot=;
void con(int u,int v)
{
b[++tot].f=h[u];
h[u]=tot;
b[tot].e=v;
b[++tot].f=h[v];
h[v]=tot;
b[tot].e=u;
return;
}
int d[MAXN],fa[MAXN],top[MAXN],siz[MAXN],z[MAXN];
void dfs(int x)
{
siz[x]=,top[x]=x;
int mac=,macc=-;
for(R int i=h[x];i;i=b[i].f)
if(!d[b[i].e])
{
d[b[i].e]=d[x]+;
fa[b[i].e]=x;
dfs(b[i].e);
siz[x]+=siz[b[i].e];
if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
}
z[x]=mac;
top[mac]=x;
return;
}
int q[MAXN],dfn[MAXN];
void dfss(int x)
{
q[++tot]=x;
dfn[x]=tot;
if(z[x])dfss(z[x]);
for(R int i=h[x];i;i=b[i].f)
if(d[b[i].e]==d[x]+&&b[i].e!=z[x])
dfss(b[i].e);
return;
}
int val[MAXN];
int fitop(int x)
{
if(top[x]==x)return x;
return top[x]=fitop(top[x]);
}
struct ahh{
int l,r,mid;
long long v,laz;
}a[*MAXN];
#define lz (i<<1)
#define rz ((i<<1)|1)
#define md a[i].mid
void build(int i,int ll,int rr)
{
a[i].l=ll;
a[i].r=rr;
if(ll==rr){a[i].v=val[q[ll]];return;}
md=(ll+rr)>>;
build(lz,ll,md);
build(rz,md+,rr);
a[i].v=min(a[lz].v,a[rz].v);
return;
}
int k;
void pushtag(int i)//啰嗦的pushtag
{
if(!a[i].laz)return;
a[i].v=a[i].laz;
if(a[i].l!=a[i].r)
{
a[lz].v=a[lz].laz=a[i].laz;
a[rz].v=a[rz].laz=a[i].laz;
}
a[i].laz=;
return;
}
void change(int i,int ll,int rr)
{
pushtag(i);//覆盖操作可不像累加有交换律啊!修改也要pushtagQAQ
if(a[i].l==ll&&a[i].r==rr){a[i].v=a[i].laz=k;return;}
if(rr<=md)change(lz,ll,rr);
else if(md+<=ll)change(rz,ll,rr);
else {change(lz,ll,md);change(rz,md+,rr);}
a[i].v=min(a[lz].v,a[rz].v);//记得一路更新上去QAQ
return;
}
long long ans;
void find(int i,int ll,int rr)
{
pushtag(i);
if(a[i].l==ll&&a[i].r==rr){ans=min(ans,a[i].v);return;}
if(rr<=md)find(lz,ll,rr);
else if(md+<=ll)find(rz,ll,rr);
else {find(lz,ll,md);find(rz,md+,rr);}
a[i].v=min(a[lz].v,a[rz].v);
return;
}
int filca(int u,int v)
{
while(top[u]!=top[v])
{
if(d[top[u]]<d[top[v]])swap(u,v);
u=fa[top[u]];
}
if(d[u]<d[v])swap(u,v);
return v;
}
int main()
{
//freopen("a.in","r",stdin);
int n,m;
scanf("%d%d",&n,&m);
for(R int i=;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
con(u,v);
}
for(R int i=;i<=n;++i)
scanf("%d",&val[i]);
int s;
scanf("%d",&s);
d[s]=;
dfs(s);
tot=;
dfss(s);
for(R int i=;i<=n;++i)
top[i]=fitop(i);
build(,,n);
int rot=s;
for(R int ew=;ew<=m;++ew)//顺手打i->疯狂WA
{
int opt;
scanf("%d",&opt);
if(opt==)
{
int id;
scanf("%d",&id);
rot=id;
}
else if(opt==)
{
int u,v;
scanf("%d%d%d",&u,&v,&k);
while(top[u]!=top[v])
{
if(d[top[u]]<d[top[v]])swap(u,v);
change(,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(d[u]<d[v])swap(u,v);
change(,dfn[v],dfn[u]);
}
else
{
int x;
scanf("%d",&x);
ans=;
if(rot==x)
find(,dfn[s],dfn[s]+siz[s]-);
else
{
int lca=filca(rot,x);
if(lca!=x)
find(,dfn[x],dfn[x]+siz[x]-);
else
{
for(R int i=h[x];i;i=b[i].f)
if(d[b[i].e]==d[x]+)
{
if(dfn[b[i].e]<=dfn[rot]&&dfn[b[i].e]+siz[b[i].e]->=dfn[rot])
{
find(,,dfn[b[i].e]-);
if(dfn[b[i].e]+siz[b[i].e]<=n)//不注意边界->疯狂RE
find(,dfn[b[i].e]+siz[b[i].e],n);
}
}
}
}
printf("%lld\n",ans);
}
}
return ;
}
把AC率丢到地上蹂躏.jpg
最新文章
- 何为HDFS?
- SecureCRT在远程主机和本地之间传输文件
- Python Day 01
- UVa 488 - Triangle Wave
- php二维数组按照键值排序的方法
- 如何把TOMCAT 添加到服务中自动启动
- find 和 locate 命令
- 【BZOJ】【2693】JZPTAB
- Cacti优化之spine轮询器
- [转] Python list、tuple、dict区别
- linux函数的阻塞与非阻塞IO及错误处理
- Callable+Future+newFixedThreadPool的应用
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用第三方组件
- 基于IIS的WCF
- 如何使用Linux的Crontab定时执行PHP脚本的方法[转载]
- Oralce 日期操作
- ubuntu更新提示/boot空间不足
- POJ3678 Katu Puzzle
- firewall-cmd --reload 防火墙
- 【BZOJ2770】YY的Treap 结论+线段树