今天早上把昨天沒編譯成功的題給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級的兩個同伴都比我厲害,興趣實驗上何凱奇各種超神,被學長學姐看好。
值得我學習的人還有很多,有很多方面我都做得不夠好,那我就每天過的開心又充實一點,
即使不開心了,看到了你的朋友圈,又格外開心了。
朋友還是如何,都很好,很有幸認識你。