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

2109人阅读 评论(0) 收藏 举报
分类:

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;
}


查看评论

bzoj4012 开店 树链剖分&主席树

看题第一眼反应点分治。。。QAQ但是从来没写过动态点分治不会写。        然后扒到了一个树链剖分的题解,发现还是可做的。        考虑一个朴素的问题,如果没有颜色限制,问所有点到u的距离之...
  • lych_cys
  • lych_cys
  • 2016-02-29 09:12:09
  • 1416

BZOJ 4012 HNOI 2015 开店(shop) 一道简单的点剖题

HNOI 2015 开店(shop) 一道简单的点剖题。 可以用c++自带函数优化代码量
  • YxuanwKeith
  • YxuanwKeith
  • 2016-03-25 12:24:47
  • 1149

bzoj4012: [HNOI2015]开店

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 思路:首先我们考虑一个简化的问题: 给定一棵树,每次询问所有点到一个点的距离和。 ...
  • thy_asdf
  • thy_asdf
  • 2015-12-18 12:23:23
  • 2650

BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r][l,r]区间内的所有点与某个点之间的距离之和,强制在线没记错的话这题我知道的有三种解法来着? (茴香豆的茴有四种写法泥萌知道嘛…?1...
  • PoPoQQQ
  • PoPoQQQ
  • 2015-04-29 12:44:38
  • 3280

BZOJ 4012 树链剖分+主席树

//By SiriusRen #include #include #include using namespace std; #define int long long #define N 30...
  • qq_31785871
  • qq_31785871
  • 2017-01-29 21:21:11
  • 390

bzoj 4012: [HNOI2015]开店 (树链剖分+主席树)

题目描述传送门题解这道题维护和求解的方法和bzoj 3924: [Zjoi2015]幻想乡战略游戏是类似的。 但是这道题有一个[L,R]的区间限制,所以我们用主席树来维护,外层是按照离散化后的xix...
  • clover_hxy
  • clover_hxy
  • 2017-04-19 18:40:55
  • 285

BZOJ4012: [HNOI2015]开店 重链剖分 可持久化线段树

http://www.lydsy.com/JudgeOnline/problem.php?id=4012 两点间距离:深度之和-2×LCA深度 http://blog.csdn.net/mima_...
  • Mima_Reincarnation
  • Mima_Reincarnation
  • 2017-06-08 19:53:25
  • 656

bzoj4012(动态点分治+卡常数)

这是一种类型的动态点分治   动态点分治,关键还是要在均摊n的空间复杂度内存下所有东西。这个就要充分利用stl,比如vector 每一个点存以这个点为根点分治的信息。   对于询问一个点的路径时,就是...
  • running_in_dark
  • running_in_dark
  • 2017-02-08 23:06:10
  • 283

BZOJ 4012 HNOI 2015 开店 动态点分治

多次询问给定点到点权在[l,r][l,r]间的所有点距离之和。询问某个点x到其他点的距离之和,可以考虑其到根的路径上的点,发现其和可以表示为(为了简单表示,令c[x]表示x所在子树内的所有点) c[...
  • huanghongxun
  • huanghongxun
  • 2016-04-03 00:10:45
  • 703

【HNOI2015】开店(shop)

题目大意给出一个n个点的二叉树。每个点、每条边都有一个权值。接下来Q个询问,每次询问所有权值为l..r之间的点到点u的最短距离之和。 题目强制在线Data Constraintn≤150000 ...
  • WorldWide_D
  • WorldWide_D
  • 2016-05-18 12:45:20
  • 679
    个人资料
    持之以恒
    等级:
    访问量: 40万+
    积分: 1万+
    排名: 1230
    文章分类
    最新评论