[BZOJ3460]Jc的宿舍

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3460]Jc的宿舍相关的知识,希望对你有一定的参考价值。

Jc的宿舍

题解

忽然发现其他人好像都是用的树上莫队做的,只有我一个打了分块。
首先,如果你没有意识到这个强制在线是假的,或者你就要强制在线做的话,那应该不会去想树上莫队的解决方法。
既然不是树上莫队,那我们要怎么做呢?当然是平衡复杂度的算法啦。

首先我们可以发现一点,对于一个固定的序列,我们先让 T i T_i Ti小的接再让 T i T_i Ti大的接一定是最优的。
事实上,每个 T i T_i Ti会对答案产生的贡献的系数是排在它后面的数的个数。
我们可以考虑对原序列进行值域分块,显然,在较小块中的点一定是比较大的块中的点先选的,也就是较大的块中每个点都会对较小块中每个点产生系数 1 1 1的贡献。
而块内自身还有相互的贡献需要处理。
事实上,对于一个块中,我们需要求出 3 3 3个东西,该块中数在路径上的点的数量,和,与其自身内部的相互贡献。
其关键还是求的该块中的数在路径上的点,而每个块在原树上的点都是 O ( S ) O\\left(S\\right) O(S)级别的,实质上其不同的路径数是比较少的。
我们不妨考虑对其建出一棵虚树出来,对虚树上的每条路径预处理出来上面的这三个量。
对于前两个量,其实 b f s bfs bfs的过程中直接加起来就可以了,而对于第三个量,可以采用可持久化线段树比较简单地进行维护。每次更改相当于在原先的有序序列中插入一个数,直接加上这个数的影响就可以了。
由于我们每次只维护一个块中的数,其实我们可以将这个块中的数都先离散化后再插入到线段树中,这样我们线段树的下标范围就只用开到 S S S了。
这样的话,我们的预处理就是 O ( n S log ⁡ S ) O\\left(nS\\log S\\right) O(nSlogS)的。

而对于每次查询,我们相当于要对于每个块都找出该路径在虚其树上对应的链。
我们可以先预处理出来所有点在虚树上最近的祖先,对于这条路径,看它端点最近的两个祖先。
如果这两个点不是祖先关系,显然这条路径就是了,否则我们可以在虚树上倍增去找由于的链。
由于虚树只有 O ( S ) O(S) O(S)的大小,虚树上倍增显然就是 O ( log ⁡ S ) O\\left(\\log S\\right) O(logS),比原树上倍增更优。
最后将不同块的答案组合起来即可。

总时间复杂度 O ( n S log ⁡ S + n m log ⁡ S S ) ⩾ O ( n m log ⁡ n ) O\\left(nS\\log S+\\fracnm\\log SS\\right)\\geqslant O\\left(n\\sqrtm\\log n\\right) O(nSlogS+SnmlogS)O(nm logn)
事实上有点卡常。

源码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double Ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e5+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=2000;
const int n1=150;
const int lim=10000000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-3;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
const int M=MAXN/n1+5,N=2*n1+5; 
int n,m,key,val[MAXN],ord[MAXN],block[MAXN],L[MAXN],R[MAXN];
int dfn[MAXN],rd[MAXN],idx,dep[MAXN],root[N],ort[MAXN],b[MAXN],totb;
int sta[MAXN],stak,st[MAXN],stk,p[M][N],len[M];
int imp[MAXN],head[MAXN],tot,f[MAXN][20],ff[M][N][10],ip[M][MAXN];
LL dis[M][N][N],ct[M][N][N],sm[M][N][N],lastans;
bool vis[MAXN];vector<int>G[N];queue<int>q;
struct edgeint to,nxt;e[MAXN<<1];
void addEdge(int u,int v)e[++tot]=(edge)v,head[u];head[u]=tot;
void AddEdge(int u,int v)G[u].pb(v);G[v].pb(u);
bool cmp1(int x,int y)return val[x]<val[y];
bool cmp2(int x,int y)return dfn[x]<dfn[y];
void dosaka(int u,int fa)
	dfn[u]=++idx;dep[u]=dep[fa]+1;f[u][0]=fa;
	for(int i=1;i<16;i++)f[u][i]=f[f[u][i-1]][i-1];
	for(int i=head[u];i;i=e[i].nxt)dosaka(e[i].to,u);
	rd[u]=idx;

int lca(int a,int b)
	if(dep[a]>dep[b])swap(a,b);
	for(int i=15;i>=0;i--)if(dep[f[b][i]]>=dep[a])b=f[b][i];
	if(a==b)return a;
	for(int i=15;i>=0;i--)if(f[a][i]^f[b][i])a=f[a][i],b=f[b][i];
	return f[a][0];

struct mingint lson,rson,cnt;LL sum;;
class SegmentTree
	private:
		ming tr[MAXN*25];int tott;
	public:
		void insert(int &now,int las,int l,int r,int ai)
			if(l>r||l>ai||r<ai)return ;
			tr[now=++tott]=tr[las];tr[now].cnt++;tr[now].sum+=b[ai];
			if(l==r)return ;int mid=l+r>>1;
			if(ai<=mid)insert(tr[now].lson,tr[las].lson,l,mid,ai);
			if(ai>mid)insert(tr[now].rson,tr[las].rson,mid+1,r,ai);
		
		int queryCnt(int rt,int l,int r,int al,int ar)
			if(l>r||l>ar||r<al||al>ar||!rt)return 0;
			if(al<=l&&r<=ar)return tr[rt].cnt;
			int mid=l+r>>1,res=0;
			if(al<=mid)res+=queryCnt(tr[rt].lson,l,mid,al,ar);
			if(ar>mid)res+=queryCnt(tr[rt].rson,mid+1,r,al,ar);
			return res;
		
		LL querySum(int rt,int l,int r,int al,int ar)
			if(l>r||l>ar||r<al||al>ar||!rt)return 0;
			if(al<=l&&r<=ar)return tr[rt].sum;
			int mid=l+r>>1;LL res=0;
			if(al<=mid)res+=querySum(tr[rt].lson,l,mid,al,ar);
			if(ar>mid)res+=querySum(tr[rt].rson,mid+1,r,al,ar);
			return res; 
		
		void clear()for(int i=1;i<=tott;i++)tr[i].lson=tr[i].rson=tr[i].cnt=tr[i].sum=0;tott=0;
T;
signed main()
	read(n);read(m);read(key);
	for(int i=1;i<=n;i++)read(val[i]),ord[i]=i;
	for(int i=1,x;i<=n;i++

以上是关于[BZOJ3460]Jc的宿舍的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3640: JC的小苹果

bzoj 3640 JC的小苹果

BZOJ3640JC的小苹果 概率DP+高斯消元

●BZOJ 3640 JC的小苹果

bzoj3316 JC loves Mkk题解

bzoj3316: JC loves Mkk