10.24日记

  今天早上把昨天没编译成功的题给A了,cf961D,是一道主席树的题,四种操作,每一种操作需要一天,分别是加入重要度为xi的ai任务,删除ai任务,查询重要度比ai小的数量,取消之前x天的操作,xi的范围属于1e9,我们发现查询只需要一个重要程度即可,也就是说我们对于ai任务,需要知道它每时每刻的重要程度,那么显然是要开一颗树来维护的,而对于一个重要程度,查询比他小的儿子数量,也是要开一棵树的,再加上有天数这一维的限制,那么我们就需要考虑开两颗主席树了,一颗对应着名字开一维map对应的重要程度,另一颗维护各个重要程度的数量,这样对于取消x天的操作,就不需要担心重合处理的问题了。

但是由于本人基础较差,对主席树的理解不到位,不敢去想象开1e9的大小,但实际上我们开主席树的时候,每次加的空间固定是logn的,而这个n取决于你选择的左右区间的大小,即使是选择了1e9,也不过32的空间大小,和线段树之类的有本质上的区别,这时候需要的复杂度就是加入数据的次数*32,所以开主席树非常轻松,需要注意的是可以简化操作,细节代码中有体现。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;string s1,s2;map<string,int>mp;
const int maxn=1e5+7;
int Q,num=0,cnt=0,rt[maxn],wt[maxn];
int get_mp(string s3)
{
	if(mp.count(s3)) return mp[s3];
	mp[s3]=++num;return num;
}
struct node{
	int l,r,sum;
}t[maxn*3*32*2];
int quiry(int x,int l,int r,int ll,int rr)
{
	if(ll<=l&&rr>=r) return t[x].sum;
	int mid=(l+r)/2,ans=0;
	if(ll<=mid) ans=quiry(t[x].l,l,mid,ll,rr);
	if(rr>mid) ans+=quiry(t[x].r,mid+1,r,ll,rr);
	return ans;
}
void change(int &x,int l,int r,int pos,int val)
{
	t[++cnt]=t[x];x=cnt;t[x].sum+=val;
	if(l==r) return ;int mid=(l+r)/2;
	if(pos<=mid) change(t[x].l,l,mid,pos,val);
	else change(t[x].r,mid+1,r,pos,val);
}
int main()
{
	scanf("%d",&Q);
	for(int i=1;i<=Q;++i)
	{
		cin>>s1;int x;
		rt[i]=rt[i-1];wt[i]=wt[i-1];
		if(s1[0]=='s')
		{
			cin>>s2;
			int id=get_mp(s2);scanf("%d",&x);
			int p1=quiry(wt[i],1,1e9,id,id);
			change(wt[i],1,1e9,id,x-p1);
			if(p1) change(rt[i],1,1e9,p1,-1);
			change(rt[i],1,1e9,x,1);
		}
		if(s1[0]=='q')
		{
			cin>>s2;int id=get_mp(s2);
			int p1=quiry(wt[i],1,1e9,id,id);
			if(p1>1) printf("%d\n",quiry(rt[i],1,1e9,1,p1-1));
			else if(p1==1) printf("0\n");
			else printf("-1\n");
			cout<<flush;
		}
		if(s1[0]=='r')
		{
			cin>>s2;int id=get_mp(s2);
			int p1=quiry(wt[i],1,1e9,id,id);
			if(p1==0) continue;
			change(wt[i],1,1e9,id,-p1);
			change(rt[i],1,1e9,p1,-1);
		}
		if(s1[0]=='u')
		{
			scanf("%d",&x);
			rt[i]=rt[i-x-1];wt[i]=wt[i-x-1];
		}
	}
	return 0;
}

ac之后神清气爽,然后做了一道网络流的题[CQOI2012]交换棋子,因为思路比较好想,这里就直接贴代码了。

一开始以为只能四个方向,还wa了一次

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;queue<int>q;
const int maxn=407*3,maxm=maxn*30;
int n,m;string s1[22],s2[22],s3[22];int ans=0,nxt[maxm];
int xt[8]={1,-1,0,0,1,1,-1,-1},yt[8]={0,0,1,-1,1,-1,1,-1},
to[maxm],cnt=1; 
int w[maxm],v[maxm],head[maxn],s,t,d[maxn],a[maxn],inq[maxn];
int co[maxn],fr[maxm],flag=0,num1=0,num2=0,anum=0;
void add_edge(int x,int y,int z,int zz)
{
	nxt[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;v[cnt]=zz;
	fr[cnt]=x;
	nxt[++cnt]=head[y];head[y]=cnt;to[cnt]=x;w[cnt]=0;v[cnt]=-zz;
	fr[cnt]=y;
}
int inp(int x,int y)
{
	return ((x-1)*m+y)*3+1;
}
int mip(int x,int y)
{
	return ((x-1)*m+y)*3+2;
}
int otp(int x,int y)
{
	return ((x-1)*m+y)*3+3;
} 
bool judge(int x,int y)
{
	if(x<1||y<1||x>n||y>m) return 0;
	else return 1;
}
void dinic()
{
	while(1)
	{
		for(int i=1;i<=t;++i) a[i]=0;
		for(int i=1;i<=t;++i) d[i]=1e9;
		d[s]=0;a[s]=1e9;q.push(s);
		while(q.size())
		{
			int x=q.front();q.pop();inq[x]=0;
			for(int i=head[x];i;i=nxt[i])
			{
				int u=to[i];
				if(w[i]<=0||d[u]<=d[x]+v[i]) continue;
				d[u]=d[x]+v[i];a[u]=min(w[i],a[x]);co[u]=i;
				if(inq[u]) continue;inq[u]=1;q.push(u);
			}
		}
		if(!a[t]) return ;ans+=a[t]*d[t];anum+=a[t];int y=t;
		while(y!=s)
		{
			y=co[y];
			w[y]-=a[t];w[y^1]+=a[t];
			y=fr[y];
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);s=(n*m+1)*3+1;t=s+1;
	for(int i=1;i<=n;++i) cin>>s1[i];
	for(int i=1;i<=n;++i) cin>>s2[i];
	for(int i=1;i<=n;++i) cin>>s3[i];
	for(int i=1;i<=n;++i)
	 for(int j=1;j<=m;++j)
	 {
	 	int wi=s3[i][j-1]-'0',k1=s1[i][j-1]-'0',k2=s2[i][j-1]-'0';
	 	add_edge(inp(i,j),mip(i,j),wi/2,0);
	 	add_edge(mip(i,j),otp(i,j),wi/2,0);
	 	for(int z=0;z<=7;++z)
	 	{
	 		int xx=i+xt[z],yy=j+yt[z];
	 		if(!judge(xx,yy)) continue;
	 		add_edge(otp(i,j),inp(xx,yy),1e9,1);
	 	}
	 	if(k1^k2==0) continue;flag=1;
	 	if(k1==1) 
		{
			add_edge(s,mip(i,j),1,0);num1++;
			add_edge(mip(i,j),otp(i,j),wi%2,0); 	
		} 
		else 
		{
			add_edge(mip(i,j),t,1,0);num2++;
			add_edge(inp(i,j),mip(i,j),wi%2,0);
		}
	 }
	 if(num1!=num2) {printf("-1");return 0;}  dinic();
	 if(num1>anum) printf("-1");else printf("%d",ans);
	 return 0;
}

ac完之后高数也就讲完了,早上发胶没有喷好,头特别痒,忍不住翘了下节的机导课回去洗洗头发,重新整理了一下发型,吃完了饭之后感觉特别困,今天精神感觉不是很好。

笔记本拉教室了,吃完饭回去拿了一下,丢三落四的毛病需要修改。

中午去N115休息,遇到好多法学院的学姐在那里聊天,就我一个在那里码代码有点尴尬,跑去别的教室睡了一会,但是还是没有听中国近代史教授上课睡眠效果好,真的,听教授讲课助眠效果特别好,我不是开玩笑,很认真的。

然后找了到AC自动机的题目开始做,挺模板的一道题,但是需要开高精度,高精度如果为0需要特判(poj1625)

还好只是高精加,不然我要报警了。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#define LL long long
#define uc unsigned char
using namespace std;short g[55][107][200];queue<int>q;
const int maxn=107;uc s1[55],s2[15];map<uc,int>mp;
int n,m,p,len1=0,t[maxn][55],rt=1,cnt=1,f[maxn];
bool poi[maxn];short ans[200];
void Insert(int &x,int now,int len)
{
	if(!x) x=++cnt;
	if(now==len) poi[x]=1;
	else Insert(t[x][mp[s2[now]]],now+1,len);
}
void get_f()
{
	for(int i=0;i<len1;++i)
	if(t[rt][i]) {q.push(t[rt][i]);f[t[rt][i]]=rt;}
	else t[rt][i]=rt;
	while(q.size())
	{
		int x=q.front();q.pop();
		for(int i=0;i<len1;++i)
		{
			int y=t[x][i],z=f[x];
			if(y) {q.push(y);f[y]=t[z][i];poi[y]|=poi[t[z][i]];}
			else t[x][i]=t[z][i]; 
		}
	} 
}
void get_add(short c[],short d[],short *p)
{
	for(int i=1;i<=max(c[0],d[0]);++i) c[i]+=d[i];
	c[0]=max(c[0],d[0]);
	for(int i=1;i<=c[0];++i) 
	{if(i==c[0]&&c[i]>=10) c[0]++;c[i+1]+=c[i]/10;c[i]%=10;} 
	for(int i=0;i<=c[0];++i,++p) *p=c[i];  
}
int main()
{
	scanf("%d%d%d",&n,&m,&p);
	scanf("%s",s1);
	while(s1[len1]!='\0') len1++;
	for(int i=0;i<len1;++i) mp[s1[i]]=i;
	for(int i=1;i<=p;++i)
	{
		scanf("%s",s2);int len2=0;
		while(s2[len2]!='\0') len2++;
		Insert(rt,0,len2);
	}
	get_f();g[0][rt][1]=1;g[0][rt][0]=1;
	for(int i=0;i<m;++i)
	 for(int j=1;j<=cnt;++j)
	 {
	 	if(!g[i][j][0]) continue;int ki;
	 	for(int z=0;z<len1;++z)
	 	if(!poi[ki=t[j][z]]) 
		{
			short *p=&g[i+1][ki][0];
		 	get_add(g[i+1][ki],g[i][j],p);	
		}
	 }
	
	for(int i=1;i<=cnt;++i) 
	{
		short *p=&ans[0];
		get_add(ans,g[m][i],p);	
	}
	if(ans[0]==0) printf("0");
	else for(int i=ans[0];i>=1;--i) printf("%d",ans[i]);
	return 0;
}

听团课,听学姐讲各种奖学金、绩点什么的,脑袋都大了。

听完之后和钟哥一起去跑跑步,有特别猛的大哥们在那里练,跑了几圈就去买了瓶饮料打算去蹭蹭课。

因为和别人一起上课的感觉很不错呀,以前我自己孤独的岁月已经让我恐惧了,我要把那些时间都补回来。

去的那个教室有学姐在自习,本来还有一哥们的,他走了,就剩我俩隔得还挺近,我感觉有点尴尬,就出去绕着北楼的花园转转圈,听听广播站的萧忆情粉丝的小姐姐深情讲解萧忆情的努力,我忍不住笑了一下。

郑晓旭是个胖胖的妹子,摄影技术一般,拍了几个秋叶发在空间,还不错,挺好看。

等我散完步回去的时候学姐已经走了,我继续啃着面包喝着汽水。

好像喝汽水的人不是很多,我不觉得有什么丢人,随时随地补充糖分非常ok。

面包不知道为什么感觉更好吃了,另外一个我明天早上检验一下,看看是不是错觉。

一学长长的挺呆萌的,以为是空教室,来上自习,他对着下午空教室的列表告诉我这里是空教室,有点懵逼。

然后我看着没怎么有人来就去图书馆了,图书馆二楼的沙发上挺不错的,人又少,声音也不嘈杂,我做竞赛题的时候对环境要求很高,不然我很难快速想到思路,然后把一道主席树的题A了,[POI2014]KUR-Couriers,稍微说一下吧,就是大于区间的一半嘛,我们每个位置都代表着一个数,那每次选择大的那个子树直到叶节点就ok了,但是会T一个点,加一个优化就行,如果当前处理到的区间和已经少于需求的,那么直接返回0就可以AC了,最慢的那个点700ms。

注意主席树本身维护着一维的性质,要善于利用才好。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=5e5+7;
int n,m,cnt=0,o[maxn],a[maxn],len,rt[maxn];
struct node{
	int l,r,sum;
}t[maxn*60];
void Insert(int &x,int l,int r,int pos)
{
	t[++cnt]=t[x];x=cnt;t[x].sum++;
	int mid=(l+r)/2;if(l==r) return ; 
	if(pos<=mid) Insert(t[x].l,l,mid,pos);
	else Insert(t[x].r,mid+1,r,pos);
}
int quiry(int x,int y,int l,int r,int p)
{
	if(t[y].sum-t[x].sum<=p) return 0;
	if(l==r) return o[l];
	int p1=t[t[y].l].sum-t[t[x].l].sum,
	p2=t[t[y].r].sum-t[t[x].r].sum,mid=(l+r)/2;
	if(p1>p2) return quiry(t[x].l,t[y].l,l,mid,p);
	else return quiry(t[x].r,t[y].r,mid+1,r,p);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) {scanf("%d",&a[i]);o[i]=a[i];} 
	sort(o+1,o+n+1);
	len=unique(o+1,o+n+1)-o-1;
	for(int i=1;i<=n;++i)
	{
		rt[i]=rt[i-1];
		Insert(rt[i],1,len,lower_bound(o+1,o+len+1,a[i])-o);
	}
	for(int i=1;i<=m;++i)
	{
		int x,y;scanf("%d%d",&x,&y);
		printf("%d\n",quiry(rt[x-1],rt[y],1,len,(y-x+1)/2));
	}
	return 0;
}

又找了一道hdu3487,打算练习一下splay,打算主要学习一下数论和splay,有一对情侣在我隔壁的椅子上说悄悄话,整的我挺烦的(单身狗的愤怒),做题也慢了一点,电脑没电了就来六楼用用学校的电脑,就是我现在在敲博客的电脑,问了一下旁边的同学怎么开,屏幕挺大也挺伤眼的,九点半才A了,就是查询模板题,splay旋转的是特定点,复杂度我一直不知道该怎么算。

另外这题的格式也挺烦的。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=3e5+7;string s1;
int n,m,num=0,son[maxn],t[maxn][2],a[maxn],fa[maxn],rt=1;
int rev[maxn],sta[maxn],b[maxn],na=0;
void downit(int x)
{
	if(!rev[x]) return ;rev[x]=0;
	int l=t[x][0],r=t[x][1];
	if(l) {rev[l]^=1;swap(t[l][0],t[l][1]);} 
	if(r) {rev[r]^=1;swap(t[r][0],t[r][1]);}
}
void up(int x)
{
	son[x]=son[t[x][0]]+son[t[x][1]]+1;
}
void dfs(int x)
{
	downit(x);
	if(t[x][0]) dfs(t[x][0]);
	if(a[x]) b[++na]=a[x];
	if(t[x][1]) dfs(t[x][1]);
	fa[x]=t[x][0]=t[x][1]=son[x]=0;
}
int find_rank(int x,int rank)
{
	downit(x);
	int sum=son[t[x][0]]+1;
	if(sum==rank) return x;
	else if(sum>rank) return find_rank(t[x][0],rank);
	else return find_rank(t[x][1],rank-sum);
}
void rotate(int x,int &k)
{
	int y=fa[x],z=fa[y],d=t[y][1]==x;
	if(y!=k) t[z][t[z][1]==y]=x;
	else k=x;
	fa[t[x][d^1]]=y;t[y][d]=t[x][d^1];t[x][d^1]=y;
	fa[y]=x;fa[x]=z;up(y);up(x);
}
void splay(int x,int &k) 
{
	int y=x,z=0;sta[++z]=x;
	while(fa[y]) sta[++z]=y=fa[y];
	while(z) downit(sta[z--]);
	while(x!=k)
	{
		int y=fa[x],z=fa[y];
		if(y!=k) rotate((t[y][1]==x)^(t[z][1]==y)?x:y,k);
		rotate(x,k);
	}
}
void solve()
{
	son[1]=1;a[1]=0;son[0]=0;rt=1;na=0;
	for(int i=1;i<=n;++i)
	{
		fa[i+1]=i;t[i][1]=i+1;son[i+1]=1;up(i);
		splay(i+1,rt);a[i+1]=i; 
	}
	fa[n+2]=n+1;son[n+2]=1;t[n+1][1]=n+2;
	up(n+1);a[n+2]=0;
	for(int i=1;i<=m;++i)
	{
		int x,y,z;cin>>s1;scanf("%d%d",&x,&y);
		if(s1[0]=='F') 
		{
			int xx=find_rank(rt,x),yy=find_rank(rt,y+2);
			splay(xx,rt);splay(yy,t[xx][1]);
			int p=t[yy][0];rev[p]^=1;swap(t[p][0],t[p][1]);
		}
		else
		{
			scanf("%d",&z);
			int xx=find_rank(rt,x),yy=find_rank(rt,y+2);
			splay(xx,rt);splay(yy,t[xx][1]);
			int p=t[yy][0];t[yy][0]=0;fa[p]=0;
			up(yy);up(xx);
			int zz1=find_rank(rt,z+1),zz2=find_rank(rt,z+2);
			splay(zz1,rt);splay(zz2,t[zz1][1]);
			t[zz2][0]=p;fa[p]=zz2;up(zz2);up(zz1);
		}
	}
	dfs(rt);for(int i=1;i<=n;++i) {printf("%d",b[i]);if(i!=n) printf(" ");}
}
int main()
{
	scanf("%d%d",&n,&m);
	while(n!=-1) {solve();printf("\n");scanf("%d%d",&n,&m);} 
	return 0;
}

七点左右的时候我买了两个域名,zhaoyifan520.com,zhaoyifan.xyz,前面的23块,后面的8块,一年有效,一会回去还得拍一下身份证认证一下,以后有博客我就放那上面了,emm,这个域名嘛,我想放下,又不想放下,想去追逐,却不知道该怎么追逐,一切随缘吧,我还不够成熟,我有那么多值得学习和努力超越的目标。

运动上师哥简直神猛13分3000米,ACM上18级的两个同伴都比我厉害,兴趣实验上何凯奇各种超神,被学长学姐看好。

值得我学习的人还有很多,有很多方面我都做得不够好,那我就每天过的开心又充实一点,

即使不开心了,看到了你的朋友圈,又格外开心了。

朋友还是如何,都很好,很有幸认识你。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章