您的位置:首页 > 其它

【BZOJ】【3052】【WC2013】糖果公园

2015-01-26 23:50 274 查看

树分块

  老早(大约一个月以前?)就听说这道神题了……orz rausen

  一直拖到现在才做……发现还是不会呢= = 只好也去Orz了Hzwer和zky

  http://hzwer.com/5250.html  /article/1560261.html
  这个树上莫队真的蛮神奇的……

  1.对于每个查询,记录它是在第几次修改之后的;

  2.以左端点所在块为第一关键字、右端点所在块为第二关键字、时间(第几次修改之后的查询)为第三关键字进行排序;

  3.对于每个查询,先进行时间上的移动(这个只需对变化了的点进行单点修改即可,有点小Z的袜子中 +1-1的感觉)再进行查询序列的移动(用之前讲的vfk的方法……)至于第二步就跟普通的树分块一样了么……

注意:由于时间移动既有向前也有向后的,所以除了要记录是把哪个点变成了什么糖果,还要记录变化前的原来的状态(时光回溯时用)(用“时光回溯”这个名字是不是十分高大上~~)

错误:1.所有数据点的答案范围都是long long!!

   2.读入单点修改糖果种类的时候,pre[x]=y; 写成了 pre[c2]=y; QAQ唉细节啊细节!!!pre数组是对点进行“时光回溯”保存的,不是对修改序号进行保存!!!理解不到位啊……(白问大视野要数据了……)

/**************************************************************
Problem: 3052
User: Tunix
Language: C++
Result: Accepted
Time:117744 ms
Memory:25256 kb
****************************************************************/

//BZOJ 3052
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;

int getint(){
int v=0,sign=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();}
while(isdigit(ch)) {v=v*10+ch-'0'; ch=getchar();}
return v*=sign;
}
typedef long long LL;
/******************tamplate*********************/
const int N=100086;
LL w
,v
;
int n,m,Q;
int head
,next[N<<1],to[N<<1],cnt;
void add(int x,int y){
to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt;
}
/*******************edge************************/
int B;
int st
,top,deep
,belong
,tot;
int fa
[25],bin[25];
void dfs(int x){
int bottom=top;
F(i,1,20)
if(deep[x]>=bin[i])
fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
for(int i=head[x];i;i=next[i])
if (to[i]!=fa[x][0]){
fa[to[i]][0]=x;
deep[to[i]]=deep[x]+1;
dfs(to[i]);
if(top-bottom>=B){
++tot;
while(top!=bottom)
belong[st[top--]]=tot;
}
}
st[++top]=x;
}
int LCA(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;bin[i]<=t;i++)
if(t&bin[i]) x=fa[x][i];
D(i,20,0)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if(x==y) return x;
return fa[x][0];
}
/*********************dfs&&LCA******************/
struct ques{
int x,y,ti,num;
bool operator < (const ques&now)const{
if(belong[x]==belong[now.x]){
if(belong[y]==belong[now.y]) return ti<now.ti;
else return belong[y]<belong[now.y];
}
else return belong[x]<belong[now.x];
}
}q
;
struct Time{
int x,y,pre;
}change
;
int pre
;

LL ans=0,answer
;
int c
,num
,now;
bool used
;
/*****************分块变量声明******************/
void work(int x){
if (used[x]){
ans-=v[c[x]]*w[num[c[x]]]; num[c[x]]--; used[x]=0;
}
else{
num[c[x]]++; ans+=v[c[x]]*w[num[c[x]]]; used[x]=1;
}
}
void Xor(int x,int y){
while(x!=y)
if(deep[x]>deep[y]) {work(x);x=fa[x][0];}
else {work(y); y=fa[y][0];}
}
void Change(int x,int y){//将点x的糖果改为第y种 (权值改为y)
if(used[x]){work(x); c[x]=y; work(x);}
else c[x]=y;
}
void TimeMachine(int tarti){
for(int i=now+1;i<=tarti;i++) Change(change[i].x,change[i].y);
for(int i=now;i>tarti;i--) Change(change[i].x,change[i].pre);
now=tarti;
}
/*****************分块函数声明******************/
int main(){
bin[0]=1; F(i,1,20) bin[i]=bin[i-1]<<1;

n=getint(); m=getint(); Q=getint();
B=pow(n,2.0/3.0);
int x,y;
F(i,1,m) v[i]=getint();//美味指数
F(i,1,n) w[i]=getint();//新奇指数
F(i,2,n){
x=getint(); y=getint();
add(x,y);
}

dfs(1);
tot++;
while(top) belong[st[top--]]=tot;
F(i,1,n) pre[i]=c[i]=getint();//每个节点的糖果种类

int cmd,c1=0,c2=0;
F(i,1,Q){
cmd=getint(); x=getint(); y=getint();
if (cmd){
c2++;
if(belong[x]>belong[y]) swap(x,y);
q[c2]=(ques){x,y,c1,c2};//记录是第几次修改之后的查询
}
else{
c1++;
change[c1]=(Time){x,y,pre[x]};
pre[x]=y;
//有点前向星的感觉,pre[i]保存第i个节点当前是什么种类的糖果
}
}
sort(q+1,q+c2+1);
//读入&&初始化 end

int lca=LCA(q[1].x,q[1].y);
TimeMachine(q[1].ti);
Xor(q[1].x,q[1].y);
work(lca);
answer[q[1].num]=ans;
work(lca);
F(i,2,c2){
TimeMachine(q[i].ti);
Xor(q[i-1].x,q[i].x);
Xor(q[i-1].y,q[i].y);
lca=LCA(q[i].x,q[i].y);
work(lca);
answer[q[i].num]=ans;
work(lca);
}
F(i,1,c2) printf("%lld\n",answer[i]);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: