bzoj3052糖果公园

树上修改莫队算法

非常好的一道题,其实应该把部分分都写一次

前30分是送的

50分是最普通的莫队算法

70分是clj的选择,也就是树上不修改莫队

100分是树上修改莫队


其实我昨天晚上睡觉的时候意识到第二天要很早起来写糖果公园但是还是没有意识到这个题的恶心之处,第一次写完貌似有9k。。。

然后赶紧缩,最后好不容易到了7k左右,不记得了。。。

很经典很神的算法,只不过因为程序太长了所以我不得不采用和标程对拍中间结果的办法来检查程序,如果这是在考场上那么我会毫不犹豫的选择哪个50分


不得不说艾神的题很复杂,而且我也看了vfk的题解。。。。

就这么多吧,似乎看了题解的人没资格讲做法,具体的去看vfk

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

#define Size (int)pow(n,2.0/3)
#define MAX 200010
#define ll long long

using namespace std;

int n,m,k,ind,BlockSize=0;
int cnt[MAX],pos[MAX];
int deep[MAX];
ll ans;
bool vis[MAX]={0};
int father[MAX],f[MAX][20];
int logg[MAX];
int wait[MAX],waitting=0;
ll val1[MAX],val2[MAX];


vector<int>candy[MAX];
vector<int>edge[MAX];
vector<int>::iterator now[MAX];

struct wbysr_change
{
	int a,b;
}op[MAX];

struct wbysr
{
	int l,r,id;
	ll ans;
}ask[MAX];


void debug_()
{
	for(int i=1;i<=n;i++)
	{
		printf("----%d\n",i);
		for(int j=0;j<edge[i].size();j++)
			printf("%d ",edge[i][j]);
		printf("\n");
		for(int j=0;j<candy[i].size();j++)
			printf("%d ",candy[i][j]);
		printf("\n");
	}
	//printf("debug done\n");
	for(int i=1;i<=n;i++)
		printf("%d %d\n",i,pos[i]);
}

int dfs(int x)
{
//	printf("fuck %d\n",x);
	int sum=0;
	/*for(int i=0;i<edge[x].size();i++)
		if(!deep[i])
		{
			father[i]=x;
			deep[i]=deep[x]+1;
			f[i][0]=x;
			for(int j=1;j<=18;j++)
				f[i][j]=f[f[i][j-1]][j-1];
			sum+=dfs(i);
			if(sum>=Size)
			{
				BlockSize++;
				while(sum--)
					pos[wait[waitting--]]=BlockSize;
				sum=0;
			}
		}*/

	///*
	for(vector<int>::iterator i=edge[x].begin();i!=edge[x].end();i++)
	if(0==deep[*i])
	{
		father[*i]=x;
		deep[*i]=deep[x]+1;
		f[*i][0]=x;
		for(int j=1;j<=18;j++)
			f[*i][j]=f[f[*i][j-1]][j-1];
		sum+=dfs(*i);
		if(sum>=Size)
		{
			BlockSize++;
			while(sum--)
				pos[wait[waitting--]]=BlockSize;//printf("ooooooooooo%d %d\n",wait[waitting+1],pos[wait[waitting+1]]);
			sum=0;
		}
	}//*/
	wait[++waitting]=x;
	return ++sum;
}


bool sort_ask(wbysr a1,wbysr a2)
{
	if(pos[a1.l]!=pos[a2.l])
		return pos[a1.l]<pos[a2.l];
	else
		if(pos[a1.r]!=pos[a2.r])
			return pos[a1.r]<pos[a2.r];
	return a1.id<a2.id;
}

void init()
{
	scanf("%d%d%d",&n,&m,&k);

	//read
	for(int i=1;i<=m;i++)
		scanf("%lld",&val1[i]);
	for(int i=1;i<=n;i++)
		scanf("%lld",&val2[i]);
	for(int i=1,a1,a2;i<=n-1;i++)
	{
		scanf("%d%d",&a1,&a2);
		edge[a1].push_back(a2);
		edge[a2].push_back(a1);
	}
	for(int i=1,w;i<=n;i++)
	{
		scanf("%d",&w);
		candy[i].push_back(w);
	}
	ind=0;
	for(int i=1,c;i<=k;i++)
	{
		scanf("%d",&c);
		if(0==c)
		{
			scanf("%d%d",&op[i].a,&op[i].b);
			candy[op[i].a].push_back(op[i].b);
		}
		else
		{
			ind++;
			scanf("%d%d",&ask[ind].l,&ask[ind].r);
			ask[ind].id=i;
//			printf("====================%d %d\n",ask[ind].l,ask[ind].r);
		}
	}
//	printf("sfddddddddd\n");

	//before done
	for(int i=1;i<=n;i++)
		now[i]=candy[i].begin();
	deep[1]=1;
	dfs(1);
//	printf("888888888888888888888\n");
//	while(waitting)
//		pos[wait[waitting--]]=BlockSize;
	for(int i=2;i<=n;i++)
		logg[i]=logg[i-1]+(i==(i&-i));
//	for(int i=1;i<=ind;i++)
//		if(pos[ask[i].l]>pos[ask[i].r])
//			swap(ask[i].l,ask[i].r);
	sort(ask+1,ask+1+ind,sort_ask);
	//debug();

//	for(int i=1;i<=ind;i++)
//		printf("++++++++++++++++++%d %d\n",ask[i].l,ask[i].r);
}

void xor_point(int x)
{
	if(vis[x])
	{
		int c=*now[x];
		ans-=val1[c]*val2[cnt[c]];
		cnt[c]--;
		vis[x]=0;
		//ans+=val1[c]*val2[cnt[c]];
	}
	else
	{
		int c=*now[x];
		cnt[c]++;
		ans+=val1[c]*val2[cnt[c]];
		vis[x]=1;
		//ans-=val1[c]*val2[cnt[c]];
	}
	return;
}

void xor_path(int a,int b)
{
	if(deep[a]<deep[b])
		swap(a,b);
	while(deep[a]!=deep[b])
	{
		xor_point(a);
		a=father[a];
	}
	while(a!=b)
	{
		xor_point(a);
		xor_point(b);
		a=father[a];
		b=father[b];
	}
}


int LCA(int a,int b)
{
	//printf("LCA begin\n");
	if(deep[a]<deep[b])
		swap(a,b);
	for(int i=logg[deep[a]];i>=0;i--)
		if(deep[f[a][i]]>=deep[b])
			a=f[a][i];
	if(a==b)
		return a;
	for(int i=logg[deep[a]];i>=0;i--)
		if(f[a][i]!=f[b][i])
		{
			a=f[a][i];
			b=f[b][i];
		}
	//printf("LCA end\n");
	return father[a];
}


ll work(int a,int b)
{
	int lca=LCA(a,b);
	//printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%d %d %d\n",a,b,lca);
	xor_point(lca);
	ll tot=ans;
//	printf("%lld\n",tot);
	xor_point(lca);
	return tot;
}


void captail_mo()
{
	for(int i=1,l=1,r=1,time=0;i<=ind;i++)
	{
	//	printf("%d %d %d %d %d\n",ask[i].id,ask[i].l,ask[i].r,l,r);
		while(time<ask[i].id)
		{
			int p=op[++time].a;
			if(!p)
				continue;
			bool flag=vis[p];
			if(flag)
				xor_point(p);
			++now[p];
			if(flag)
				xor_point(p);
		}
		
		while(time>ask[i].id)
		{
			int p=op[time--].a;
			if(!p)
				continue;
			bool flag=vis[p];
			if(flag)
				xor_point(p);
			now[p]--;
			if(flag)
				xor_point(p);
		}
		xor_path(l,ask[i].l);
		xor_path(r,ask[i].r);
		l=ask[i].l;
		r=ask[i].r;
	//	printf("MO\n");
		ask[i].ans=work(l,r);
	}
}


bool cmp_end(wbysr a1,wbysr a2)
{
	return a1.id<a2.id;
}

void print()
{
	sort(ask+1,ask+1+ind,cmp_end);
	for(int i=1;i<=ind;i++)
		printf("%lld\n",ask[i].ans);
	return;
}

void da()
{
	for(int i=1;i<=k;i++)
		if(ask[i].l>ask[i].r)
			swap(ask[i].l,ask[i].r);
	return;
}


int main()
{
	init();
	//printf("------------------init\n");
//	da();
	captail_mo();
	//printf("------------------captail_mo");
	print();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值