码迷,mamicode.com
首页 > 其他好文 > 详细

二进制分组

时间:2020-06-03 12:07:33      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:scan   字符   ref   ble   return   ret   vector   clu   数字   

是一种以一个\(log\)为代价,解决一类强制在线带修改问题的方法

如果不强制在线,我们可以用各种姿势奇奇怪怪的分治做法

基本思想是我们将一个查询前的修改操作按二进制分组,例如某个询问前有\(23\)个修改操作,那么我们将这些修改操作分为大小为\(16,4,2,1\)的四组

当新加入一个修改时,我们在右侧加入一个\(1\)得到\(16,4,2,1,1\)

当最右侧两个组大小相等时,将其合并为同一组得到\(16,4,2,2\),最终合并为\(16,8\)

如果合并两个组的代价是组内元素大小的话,那么修改总复杂度将是\(O(nlogn)\),每个元素合并一次会花费一个复杂度的代价,显然一个元素最多被合并\(log\)

最多同时存在\(log\)组修改操作,假设计算一组修改的复杂度是\(O(k)\),那么询问操作的复杂度是\(O(nklogn)\)

CF710F

字符串匹配通过\(AC\)自动机实现,按照上面的方法开\(log\)\(AC\)自动机

删除操作可以视为再开一份\(AC\)自动机,用总答案减去删除的的答案

注意\(AC\)自动机因为要合并,所以\(trie\)树和补图要同时维护,每次合并\(trie\)树后重新建立补图

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<‘0‘||ch>‘9‘)&&ch!=‘-‘;ch=getchar());
		if(ch==‘-‘) f=0,ch=getchar();
		while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
		return f?x:-x;
	}
	const int N=3e5+10,p=1e9+9;
	int Q;
	char s[N];
	struct ACM
	{
		int son[N][26],fail[N],num[N],tot[N],vis[N][26];
		int rt[N],top,cnt,siz[N];
		inline int merge(int x,int y)
		{
			if(!x||!y) return x|y;
			tot[x]+=tot[y];
			for(int i=0;i<26;++i) son[x][i]=merge(son[x][i],son[y][i]);
			return x;
		}
		inline void getfail(int rt)
		{
			queue<int> q;
			for(int i=0;i<26;++i)
			{
				if(son[rt][i]) vis[rt][i]=son[rt][i],fail[son[rt][i]]=rt,q.push(vis[rt][i]);
				else vis[rt][i]=rt;
			}
			while(!q.empty())
			{
				int now=q.front();q.pop();
				for(int i=0;i<26;++i)
				{
					if(son[now][i])
					{
						vis[now][i]=son[now][i],fail[son[now][i]]=vis[fail[now]][i];
						q.push(vis[now][i]);
					}
					else vis[now][i]=vis[fail[now]][i];
				}
				num[now]=tot[now]+num[fail[now]];
			}
		}
		inline void insert(char *s)
		{
			rt[++top]=++cnt,siz[top]=1;
			int now=rt[top];
			for(int i=1,len=strlen(s+1);i<=len;++i)
			{
				int c=s[i]-‘a‘;
				if(!son[now][c]) son[now][c]=++cnt;
				now=son[now][c];
			}
			tot[now]=1;
			while(siz[top]==siz[top-1]) --top,rt[top]=merge(rt[top],rt[top+1]),siz[top]+=siz[top+1];
			getfail(rt[top]);
		}
		inline int query(char *s)
		{
			int ret=0,len=strlen(s+1);
			for(int i=1;i<=top;++i)
			{
				int now=rt[i];
				for(int j=1;j<=len;++j)
				{
					now=vis[now][s[j]-‘a‘];
					ret+=num[now];
				}
			}
			return ret;
		}
	}A,B;
	inline void main()
	{
		Q=read();
		for(int opt,i=1;i<=Q;++i)
		{
			opt=read();scanf("%s",s+1);
			if(opt==1) A.insert(s);
			if(opt==2) B.insert(s);
			if(opt==3) printf("%lld\n",A.query(s)-B.query(s));
			fflush(stdout);
		}
	}
}
signed main()
{
	red::main();
	return 0;
}

[SDOI2014]向量集

设询问向量为\((x_0,y_0)\),点积为\(x_0*x+y_0*y\)

\(ans=max\{y_0*\frac{x_0}{y_0}x+y\}\)

我们假设\(y_0\ge 0\) 否则将所有数字取反 得到

\(ans=y_0*max\{\frac{x_0}{y_0}x+y\}\)

后面这个东西说明答案集合在上凸包上,所以我们要维护凸包

考虑二进制分组,用线段树的结构,每次向最新一个位置插入向量,如果线段树一个区间被填满了,就把这个区间的凸包建立出来

询问的时候在\(log\)个凸包上三分

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1) 
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<‘0‘||ch>‘9‘)&&ch!=‘-‘;ch=getchar());
		if(ch==‘-‘) f=0,ch=getchar();
		while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
		return f?x:-x;
	}
	const int N=4e5+10,inf=2e18;
	int n,ans,tot;
	char s[5];
	bool encode;
	inline void decode(int& x){x^=(ans&0x7fffffff);}
	struct node
	{
		int x,y;
		inline node operator + (const node &t) const
		{
			return (node){x+t.x,y+t.y};
		}
		inline node operator - (const node &t) const
		{
			return (node){x-t.x,y-t.y};
		}
		inline int operator * (const node &t) const
		{
			return x*t.x+y*t.y;
		}
		inline int operator ^ (const node &t) const
		{
			return x*t.y-y*t.x;
		}
		inline bool operator < (const node &t) const
		{
			return x<t.x||(x==t.x&&y<t.y);
		}
	};
	int sum[N<<2];
	vector<node> a[2][N<<2];
	node sor[N];
	int num;
	inline void merge(int p,int id)
	{
		int sum1=a[id][ls(p)].size(),sum2=a[id][rs(p)].size();
		int t1=0,t2=0;num=0;
		while(t1<sum1&&t2<sum2)
		{
			if(a[id][ls(p)][t1]<a[id][rs(p)][t2]) sor[++num]=a[id][ls(p)][t1++];
			else sor[++num]=a[id][rs(p)][t2++];
		}
		while(t1<sum1) sor[++num]=a[id][ls(p)][t1++];
		while(t2<sum2) sor[++num]=a[id][rs(p)][t2++];
		int top=0;
		for(int i=1;i<=num;++i)
		{
			while(top>1&&((a[id][p][top-1]-a[id][p][top-2])^(sor[i]-a[id][p][top-2]))>=0) a[id][p].pop_back(),--top;
			a[id][p].push_back(sor[i]);++top;
		}
	}
	inline void update(int pos,int l,int r,int p,int x,int y)
	{
		++sum[p];
		if(l==r)
		{
			a[0][p].push_back((node){x,y});
			a[1][p].push_back((node){-x,-y});
			return;
		}
		if(pos<=mid) update(pos,l,mid,ls(p),x,y);
		else update(pos,mid+1,r,rs(p),x,y);
		if(sum[p]==r-l+1) merge(p,0),merge(p,1);
	}
	inline int query(int tl,int tr,int l,int r,int p,int x,int y,int id)
	{
		if(tl<=l&&r<=tr)
		{
			int l=0,r=a[id][p].size()-1;
			node now=(node){x,y};
			while(r-l>5)
			{
				int mid1=l+(r-l)/3,mid2=r-(r-l)/3;
				if(a[id][p][mid1]*now<=a[id][p][mid2]*now) l=mid1;
				else r=mid2;
			}
			int ret=-inf;
			for(int i=l;i<=r;++i) ret=max(ret,a[id][p][i]*now);
			return ret;
		}
		int ret=-inf;
		if(tl<=mid) ret=max(ret,query(tl,tr,l,mid,ls(p),x,y,id));
		if(tr>mid) ret=max(ret,query(tl,tr,mid+1,r,rs(p),x,y,id));
		return ret;
	}
	inline void main()
	{
		n=read();scanf("%s",s);
		encode=s[0]!=‘E‘;
		for(int x,y,l,r,i=1;i<=n;++i)
		{
			scanf("%s",s);
			x=read(),y=read();
			if(encode) decode(x),decode(y);
			if(s[0]==‘A‘) update(++tot,1,n,1,x,y);
			else
			{
				l=read(),r=read();
				if(encode) decode(l),decode(r);
				if(y>=0) printf("%lld\n",ans=query(l,r,1,n,1,x,y,0));
				else printf("%lld\n",ans=query(l,r,1,n,1,-x,-y,1));
			}
		}
	}
}
signed main()
{
	//freopen("r1.in","r",stdin);
	red::main();
	return 0;
}

二进制分组

标签:scan   字符   ref   ble   return   ret   vector   clu   数字   

原文地址:https://www.cnblogs.com/knife-rose/p/13036602.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!