7.11 NOI模拟赛 qiqi20021026的T1 四个指针莫队 trie树

LINK:qiqi20021026的T1

avatar
avatar

考场上只拿到了50分的\(nq\)暴力。

考虑一个区间和一个区间配对怎么做 二分图最大带权匹配复杂度太高。

先考虑LCS的问题 常见解决方法是后缀数组/trie树.

一个贪心是 每次让贡献最大的一对配对是最优的策略。

具体证明可以利用扰动法 或者观察法。

即设\(p,q,l,r\) 分类讨论一下情况就行辣 怎么证明全局最优?可以发现任意两个匹配都是这样最优 交换会变得更差 这样应该可以说明全局最优了吧?

这个贪心直接做复杂度还是很高 可以考虑trie树上做 那么就是在LCA处匹配 匹配不了到父亲处.

这样复杂度就是\(n\cdot q\)的了.

考虑正解:写完暴力我一度认为这题感觉是一个二维莫队。

但是我发现每次多加一个字符串的贡献非常难处理 所以就不会了。

一个非常套路 且我见过很多次就是没反应过来的套路 是 观察这个贡献 后缀长度 其实可以均摊到路径上的节点上.

即对于每个节点取 min(a,b)即可得到贡献。

这样一个串就对应到了一条路径上 且每个节点的min(a,b)这种贡献都是可以O(1)计算的。

然后考虑莫队 直接 序列上(trie树此时其实也是一个序列)莫队+序列上莫队 这样一共存在四个指针。

分块的大小要调整好 可以奇偶优化分块 复杂度不太清楚 (反正轻轻松松跑过5e5

code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
#define len(x) t[x].len
using namespace std;
//无奈 太菜了 签到题都只能暴力 我真是个弱智./kk
const int MAXN=10010,maxn=500010;
int n,Q,len,cnt,ans,id=1,B=100;
int t[MAXN][26],pos[MAXN],sum[maxn],wl[MAXN],wr[MAXN],c[MAXN];
struct wy{int l,r,L,R,id;}q[maxn];
string a;
inline void insert()
{
	int now=1;
	vep(0,a.size(),i)
	{
		int ww=a[i]-'a';
		if(!t[now][ww])t[now][ww]=++id;
		now=t[now][ww];pos[++cnt]=now;
	}
}
inline int cmp(wy a,wy b)
{
	if(a.l/B!=b.l/B)return a.l<b.l;
	if(a.r/B!=b.r/B)return a.l/B&1?a.r<b.r:a.r>b.r;
	if(a.L/B!=b.L/B)return a.r/B&1?a.L<b.L:a.L>b.L;
	return a.L/B&1?a.R<b.R:a.R>b.R;
}
inline void add(int x)
{
	++c[pos[x]]>0?++ans:--ans;
}
inline void del(int x)
{
	--c[pos[x]]<0?++ans:--ans;
}
int main()
{
	//freopen("1.in","r",stdin);
	freopen("qiqi.in","r",stdin);
	freopen("qiqi.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n>>Q;
	rep(1,n,i)
	{
		a="";cin>>a;
		reverse(a.begin(),a.end());
		wl[i]=cnt+1;insert();wr[i]=cnt;
	}
	rep(1,Q,i)
	{
		int l,r;cin>>l>>r;
		q[i].l=wl[l];q[i].r=wr[r];
		sum[i]+=wr[r]-wl[l]+1;
		cin>>l>>r;q[i].id=i;
		q[i].L=wl[l];q[i].R=wr[r];
		sum[i]+=wr[r]-wl[l]+1;
	}
	sort(q+1,q+1+Q,cmp);
	int l=1,r=0,L=1,R=0;
	rep(1,Q,i)
	{
		while(l>q[i].l)add(--l);
		while(l<q[i].l)del(l),++l;
		while(L>q[i].L)del(--L);
		while(L<q[i].L)add(L),++L;
		while(r<q[i].r)add(++r);
		while(r>q[i].r)del(r),--r;
		while(R<q[i].R)del(++R);
		while(R>q[i].R)add(R),--R;
		sum[q[i].id]-=ans;
	}
	rep(1,Q,i)put(sum[i]>>1);
	return 0;
}
posted @ 2020-07-15 17:24  chdy  阅读(148)  评论(0编辑  收藏  举报