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級的兩個同伴都比我厲害,興趣實驗上何凱奇各種超神,被學長學姐看好。

值得我學習的人還有很多,有很多方面我都做得不夠好,那我就每天過的開心又充實一點,

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

朋友還是如何,都很好,很有幸認識你。

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