[动态树分治] BZOJ4012 [HNOI2015]开店

PoPoQQQhttp://blog.csdn.net/popoqqq/article/details/45365043

省选前学动态树分治 

跑起来飞快 45s+

看着提交记录 只能说惨不忍睹 爆int呆滞了一早上 还有因为没删文件 没强制在线 RE的

动态树分治 印象中还有 幻想乡战略游戏和捉迷藏 

代码注释一大片 丑我也不管了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define V G[p].v
using namespace std;
typedef long long ll;
typedef pair<int,long long> data;
typedef vector<data> abcd;

pair<ll,int> operator + (const pair<ll,int> x,const pair<ll,int> y)
{
    return make_pair(x.first+y.first,x.second+y.second);
}
pair<ll,int> operator - (const pair<ll,int> x,const pair<ll,int> y)
{
    return make_pair(x.first-y.first,x.second-y.second);
}

inline char nc() {
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x) {
	char c=nc(),b=1;
	for (; !(c>='0' && c<='9'); c=nc()) if (c=='-') b=-1;
	for (x=0; c>='0' && c<='9'; x=x*10+c-'0',c=nc());
}

inline void read(ll &x) {
	char c=nc(),b=1;
	for (; !(c>='0' && c<='9'); c=nc()) if (c=='-') b=-1;
	for (x=0; c>='0' && c<='9'; x=x*10+c-'0',c=nc());
}

inline void read(char &x) {
	for (x=nc(); x!='C' && x!='G'; x=nc());
}

namespace ST {
	int maxn;
	ll st[300005][20];
	int Log[300005];
	inline void Pre(int n,ll *a) {
		maxn=n;
		for (int i=2; i<=n; i++) Log[i]=Log[i>>1]+1;
		for (int i=1; i<=n; i++)
			st[i][0]=a[i];
		for (int k=1; k<=19; k++)
			for (int i=1; i<=n; i++) {
				st[i][k]=st[i][k-1];
				if (i+(1<<(k-1))<=maxn)
					st[i][k]=min(st[i][k-1],st[i+(1<<(k-1))][k-1]);
			}
	}
	inline ll Query(int l,int r) {
		if (l>r) swap(l,r);
		int t=Log[r-l+1];
		return min(st[l][t],st[r-(1<<t)+1][t]);
	}
}

struct edge {
	int u,v,next;
	ll w;
};

edge G[300005];
int head[150005],inum;

inline void add(int u,int v,ll w,int p) {
	G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

int n,tot,A;
int a[150005];
ll depth[150005];
int size[150005],del[150005],fat[150005];
ll ia[300005],clk;
int pos[150005];
abcd sum1[150005],sum2[150005];

inline void dfs(int u,int fa) {
	ia[++clk]=depth[u];
	pos[u]=clk;
	for (int p=head[u]; p; p=G[p].next)
		if (V!=fa)
		{
			depth[V]=depth[u]+G[p].w;
			dfs(V,u),ia[++clk]=depth[u];
		}
}

inline ll dis(int u,int v) {
	return depth[u]+depth[v]-2*ST::Query(pos[u],pos[v]);
}

int sum,rt,minimum;

inline void Root(int u,int fa) {
	int maximum=0;
	size[u]=1;
	for (int p=head[u]; p; p=G[p].next)
		if (V!=fa && !del[V]) {
			Root(V,u);
			size[u]+=size[V];
			maximum=max(maximum,size[V]);
		}
	maximum=max(maximum,sum-size[u]);
	if (minimum>maximum) minimum=maximum,rt=u;
}

inline void dfs(int u,int fa,ll d,abcd &sum1,abcd &sum2)
{
	size[u]=1;
	sum1.push_back(data(a[u],d));
	sum2.push_back(data(a[u],d));
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa && !del[V])
			dfs(V,u,d+G[p].w,sum1,sum2),size[u]+=size[V];
}

inline void Divi(int u) {
	del[u]=1;
	sum1[u].push_back(data(a[u],0));
	for (int p=head[u]; p; p=G[p].next)
		if (!del[V]) {
			abcd itmp;
			dfs(V,u,G[p].w,sum1[u],itmp);
			
			sum=size[V]; minimum=1<<30; 
			Root(V,u);
			int cg=rt;
			fat[cg]=u;
			Divi(cg);
			
			sum2[cg]=itmp;
			sum2[cg].push_back(data(-1,0));
            sort(sum2[cg].begin(),sum2[cg].end());
        	for(int j=1;j<sum2[cg].size();j++)
            	sum2[cg][j].second+=sum2[cg][j-1].second;
		}
	sum1[u].push_back(data(-1,0));
    sort(sum1[u].begin(),sum1[u].end());
    for(int j=1;j<sum1[u].size();j++)
        sum1[u][j].second+=sum1[u][j-1].second;
}

inline pair<ll,int> Query(abcd &a,int l,int r){
	if (a.empty()) 
		return pair<ll,int>(0,0);
//	for (int j=0;j<a.size();j++)
//		printf("(%d,%lld)",a[j].first,a[j].second);
//	printf("\n");
	abcd::iterator it1=lower_bound(a.begin(),a.end(),data(l,0));
    abcd::iterator it2=lower_bound(a.begin(),a.end(),data(r+1,0));
    it1--; it2--;
//    printf("(%d,%lld)\n",it1->first,it1->second);
//    printf("(%d,%lld)\n",it2->first,it2->second);
//    printf("%lld\n",it2->second-it1->second);
    return make_pair(it2->second-it1->second,it2-it1);
}

inline ll Query(int x,int l,int r){
	ll ret=Query(sum1[x],l,r).first;
	for (int i=x;fat[i];i=fat[i]){
		pair<ll,int> itmp=Query(sum1[fat[i]],l,r)-Query(sum2[i],l,r);
		ret+=itmp.first+itmp.second*dis(x,fat[i]);
	}
	return ret;
}

int main() {
	int _u,_v,Q;
	ll _w,_a,_b;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(Q); read(A);
	for (int i=1; i<=n; i++)
		read(a[i]);
	for (int i=1; i<n; i++)
		read(_u),read(_v),read(_w),add(_u,_v,_w,++inum),add(_v,_u,_w,++inum);
	dfs(1,0);
	ST::Pre(clk,ia);
	minimum=1<<30; sum=n; Root(1,0); 
	Divi(rt);
	/*for (int i=1;i<=n;i++,putchar('\n'))
		for (int j=0;j<sum1[i].size();j++)
			printf("(%d,%lld)",sum1[i][j].first,sum1[i][j].second);
	for (int i=1;i<=n;i++,putchar('\n'))
		for (int j=0;j<sum2[i].size();j++)
			printf("(%d,%lld)",sum2[i][j].first,sum2[i][j].second);*/
	ll lastans=0;
	while (Q--)
	{
		read(_u); read(_a); read(_b);
		(_a+=lastans)%=A; (_b+=lastans)%=A;
		if (_a>_b) swap(_a,_b);
		lastans=Query(_u,_a,_b);
		printf("%lld\n",lastans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值