线段树专题
poj1151 矩形面积并 离散化+排序+扫描线
int NUM,FLAG; double BIT; //long long float #define DIG(a) (((a)>='0')&&((a)<='9')) #define cind(j) { \ BIT=0.1; j=FLAG=0; NUM=getchar(); \ while(!DIG(NUM)&&NUM!='-'&&NUM!='.')NUM=getchar(); \ if(NUM=='-'){FLAG=1;NUM=getchar();} \ if(DIG(NUM)){ \ j=NUM-'0';NUM=getchar(); \ while(DIG(NUM)){j=10*j+(NUM-'0');NUM=getchar();} \ } \ if(NUM=='.'){ \ NUM=getchar(); \ while(DIG(NUM)){j+=(NUM-'0')*BIT;BIT/=10;NUM=getchar();} \ } \ if(FLAG)j=-j; \ } #define lson i<<1,a,m #define rson i<<1|1,m,b #define MaxN 205 struct Node{ int cover;//覆盖次数 double s;//被覆盖的总长度 }T[MaxN<<2]; int n,cntx,cnty; double x[MaxN],y[MaxN]; int newx[MaxN],newy[MaxN]; double hashx[MaxN],hashy[MaxN]; void UpDate(int i,int a,int b,int c,int d,int val){//(1,1,n,c,d,val) int m=(a+b)>>1; if(a==c&&b==d) T[i].cover+=val; else if(d<=m) UpDate(lson,c,d,val); else if(c>=m) UpDate(rson,c,d,val); else{ UpDate(lson,c,m,val); UpDate(rson,m,d,val); } if(T[i].cover>0) { T[i].s=hashx[b]-hashx[a]; } else if(a+1<b) { T[i].s=T[i<<1].s+T[i<<1|1].s; } else { T[i].s=0; } } struct nod{ int x1,x2,y,f;//f=1为底边 f=-1为顶边 }u[MaxN];//u为横边 bool cmp(nod n1,nod n2){return n1.y<n2.y;} struct no{ double num; int id; }lx[MaxN],ly[MaxN]; bool cmp1(no n1,no n2){return n1.num<n2.num;} void readData(){ for(int i=1;i<=n;i++){ cind(x[i<<1]);cind(y[i<<1]);cind(x[i<<1|1]);cind(y[i<<1|1]); lx[i<<1].num=x[i<<1]; lx[i<<1|1].num=x[i<<1|1]; ly[i<<1].num=y[i<<1]; ly[i<<1|1].num=y[i<<1|1]; lx[i<<1].id=ly[i<<1].id=i<<1; lx[i<<1|1].id=ly[i<<1|1].id=i<<1|1; } } void LiSan(){ sort(lx+2,lx+((n+1)<<1),cmp1); sort(ly+2,ly+((n+1)<<1),cmp1); lx[1].num=ly[1].num=-99999999; cntx=cnty=0; for(int i=2;i<=(n<<1|1);i++){ if(lx[i].num!=lx[i-1].num)cntx++; if(ly[i].num!=ly[i-1].num)cnty++; newx[lx[i].id]=cntx; newy[ly[i].id]=cnty; hashx[cntx]=lx[i].num; hashy[cnty]=ly[i].num; } for(int i=1;i<=n;i++){ u[i<<1].x1 = u[i<<1|1].x1 = newx[i<<1]; u[i<<1].x2 = u[i<<1|1].x2 = newx[i<<1|1]; u[i<<1].y=newy[i<<1]; u[i<<1|1].y=newy[i<<1|1]; u[i<<1].f=1; u[i<<1|1].f=-1; } sort(u+2,u+((n+1)<<1),cmp); } int main() { int Case=0; while(cin>>n&&n){ Case++; readData(); LiSan(); memset(T,0,sizeof(T)); double sum=0; for(int i=2;i<=(n<<1|1);i++){ UpDate(1,1,cntx,u[i].x1,u[i].x2,u[i].f); if(i<(n<<1|1))sum+=T[1].s*(hashy[u[i+1].y]-hashy[u[i].y]); } cout<<"Test case #"<<Case<<endl; cout<<"Total explored area: "<<fixed<<setprecision(2)<<sum<<endl<<endl; } return 0; }
poj 1177 矩形周长并 离散化+排序+扫描线
每处理一条横边,记录T[1]的被覆盖长度的增量,即为横着的轮廓
num记录区间内的被覆盖的段数,T[1].num*y方向的增量*2即为竖着的轮廓
int NUM,FLAG; //输入优化 #define DIG(a) (((a)>='0')&&((a)<='9')) #define cini(j) { \ j=FLAG=0; NUM=getchar(); \ while(!DIG(NUM)&&NUM!='-')NUM=getchar(); \ if(NUM=='-'){FLAG=1;NUM=getchar();} \ j=NUM-'0';NUM=getchar(); \ while(DIG(NUM)){j=10*j+(NUM-'0');NUM=getchar();} \ if(FLAG)j=-j; \ } #define lson i<<1,a,m #define rson i<<1|1,m,b #define MaxN 10005 struct Node{ int cover,s;//cover覆盖次数 s区间被覆盖长度 int num; bool left,right; }T[MaxN<<2]; int n,cntx,cnty; int x[MaxN],y[MaxN]; int newx[MaxN],newy[MaxN]; int hashx[MaxN],hashy[MaxN]; void UpDate(int i,int a,int b,int c,int d,int val){//(1,1,n,c,d,val) int m=(a+b)>>1; if(a==c&&b==d) T[i].cover+=val; else if(d<=m) UpDate(lson,c,d,val); else if(c>=m) UpDate(rson,c,d,val); else{ UpDate(lson,c,m,val); UpDate(rson,m,d,val); } if(T[i].cover>0) { T[i].s=hashx[b]-hashx[a]; T[i].left=T[i].right=true; T[i].num=1; } else if(a+1<b) { T[i].s=T[i<<1].s+T[i<<1|1].s; T[i].left=T[i<<1].left; T[i].right=T[i<<1|1].right; T[i].num=T[i<<1].num+T[i<<1|1].num; if(T[i<<1].right&&T[i<<1|1].left)T[i].num--; } else { T[i].s=0; T[i].left=T[i].right=false; T[i].num=0; } } struct nod{ int x1,x2,y,f;//f=1为底边 f=-1为顶边 }u[MaxN];//u为横边 bool cmp(nod n1,nod n2){return n1.y<n2.y;} struct no{ int num,id; }lx[MaxN],ly[MaxN]; bool cmp1(no n1,no n2){return n1.num<n2.num;} void readData(){ cini(n); for(int i=1;i<=n;i++){ cini(x[i<<1]);cini(y[i<<1]);cini(x[i<<1|1]);cini(y[i<<1|1]); lx[i<<1].num=x[i<<1]; lx[i<<1|1].num=x[i<<1|1]; ly[i<<1].num=y[i<<1]; ly[i<<1|1].num=y[i<<1|1]; lx[i<<1].id=ly[i<<1].id=i<<1; lx[i<<1|1].id=ly[i<<1|1].id=i<<1|1; } } void LiSan(){ sort(lx+2,lx+((n+1)<<1),cmp1); sort(ly+2,ly+((n+1)<<1),cmp1); lx[1].num=ly[1].num=-99999999; for(int i=2;i<=(n<<1|1);i++){ if(lx[i].num!=lx[i-1].num)cntx++; if(ly[i].num!=ly[i-1].num)cnty++; newx[lx[i].id]=cntx; newy[ly[i].id]=cnty; hashx[cntx]=lx[i].num; hashy[cnty]=ly[i].num; } for(int i=1;i<=n;i++){ u[i<<1].x1 = u[i<<1|1].x1 = newx[i<<1]; u[i<<1].x2 = u[i<<1|1].x2 = newx[i<<1|1]; u[i<<1].y=newy[i<<1]; u[i<<1|1].y=newy[i<<1|1]; u[i<<1].f=1; u[i<<1|1].f=-1; } sort(u+2,u+((n+1)<<1),cmp); } void solve(){ int t=0,t1,t2; for(int i=2;i<=(n<<1|1);i++){ t1=T[1].s; UpDate(1,1,cntx,u[i].x1,u[i].x2,u[i].f); t2=T[1].s; t+=t1>t2?t1-t2:t2-t1; if(i<(n<<1|1))t+=T[1].num*(hashy[u[i+1].y]-hashy[u[i].y])*2; } cout<<t<<endl; } int main() { readData(); LiSan(); solve(); return 0; }
poj 1823 c=1 将i开始的m个元素变为1 c=2 将i开始的m个元素变为0 c=3 输出最长的连续0的个数
每个结点存储: l:区间左边连续0的个数 r:区间右边连续0的个数 ma:区间内最大连续0的个数
int NUM,FLAG; //ÊäÈëÓÅ»¯ #define DIG(a) (((a)>='0')&&((a)<='9')) #define cini(j) { \ j=FLAG=0; NUM=getchar(); \ while(!DIG(NUM)&&NUM!='-')NUM=getchar(); \ if(NUM=='-'){FLAG=1;NUM=getchar();} \ j=NUM-'0';NUM=getchar(); \ while(DIG(NUM)){j=10*j+(NUM-'0');NUM=getchar();} \ if(FLAG)j=-j; \ } #define lson i<<1,a,m #define rson i<<1|1,m+1,b #define MaxN 16005 int n; struct Node{ int l,r,ma,s; bool lazy; }T[MaxN<<2]; void MakeTree(int i,int a,int b){//(1,a,b) T[i].l=T[i].r=T[i].ma=b-a+1; T[i].s=T[i].lazy=0; if(a<b){ int m=(a+b)>>1; MakeTree(lson); MakeTree(rson); } else{} } void PushDown(int i,int a,int b){ int m=(a+b)>>1; T[i].lazy=0; if(a<b){ T[i<<1].lazy=T[i<<1|1].lazy=1; T[i<<1].s=T[i].s; T[i<<1|1].s=T[i].s; T[i<<1].l=T[i<<1].r=T[i<<1].ma=(m-a+1)*(1-T[i<<1].s); T[i<<1|1].l=T[i<<1|1].r=T[i<<1|1].ma=(b-m)*(1-T[i<<1|1].s); } } int Max(int a,int b,int c){ int t=a>b?a:b; t=t>c?t:c; return t; } void PushUp(int i,int a,int b){ int m=(a+b)>>1; T[i].ma=Max(T[i<<1].ma,T[i<<1|1].ma,T[i<<1].r+T[i<<1|1].l); T[i].l=T[i<<1].l; T[i].r=T[i<<1|1].r; if(T[i<<1].l==(m-a+1))T[i].l+=T[i<<1|1].l; if(T[i<<1|1].r==(b-m))T[i].r+=T[i<<1].r; } void UpDate(int i,int a,int b,int c,int d,int val){//(1,1,n,c,d,val) //cout<<i<<' '<<a<<' '<<b<<' '<<c<<' '<<d<<' '<<val<<' '<<endl; if(a==c&&b==d){ T[i].s=val;T[i].lazy=1; T[i].l=T[i].r=T[i].ma=(b-a+1)*(1-val); return; } if(T[i].lazy)PushDown(i,a,b); int m=(a+b)>>1; if(d<=m){ UpDate(lson,c,d,val); } else if(c>=m+1){ UpDate(rson,c,d,val); } else{ UpDate(lson,c,m,val); UpDate(rson,m+1,d,val); } if(a<b)PushUp(i,a,b); } int main() { int p; cini(n);cini(p); MakeTree(1,1,n); int c,i,m; while(p--){ cini(c); if(c==1){ cini(i);cini(m); UpDate(1,1,n,i,i+m-1,1); } else if(c==2){ cini(i);cini(m); UpDate(1,1,n,i,i+m-1,0); } else printf("%d\n",T[1].ma); } return 0; }
poj 2155 二维线段树 A[n][n]的矩阵 元素初始化全为0 给以下两种指令:
C a b c d表示从左上角(a,b)到右下角(c,d)的矩形内元素取反
Q a b 表示询问A[a][b]的值
#define Left(i) (i<<1) #define Right(i) (i<<1|1) #define MaxN 1010 #define Mx 2400 #define My 2400 struct SubNode{ int a,b; int mid(){return (a+b)/2;} int ad; }; struct Node{ int a,b; int mid(){return (a+b)/2;} SubNode t[My]; }T[Mx]; void MakeT(int i,int j,int a,int b){ T[i].t[j].a=a; T[i].t[j].b=b; T[i].t[j].ad=0; if(a<b){ MakeT(i,Left(j),a, T[i].t[j].mid() ); MakeT(i,Right(j), T[i].t[j].mid()+1 ,b); } } void MakeTree(int i,int a,int b,int c,int d){//(1, a,b ,c,d) T[i].a=a; T[i].b=b; MakeT(i,1,c,d); if(a<b){ MakeTree(Left(i),a, T[i].mid() ,c,d); MakeTree(Right(i), T[i].mid()+1,b,c,d); } } int flag; void query(int i,int j,int b){ if(T[i].t[j].ad) flag^=1; if(b==T[i].t[j].a&&T[i].t[j].b==b)return; if(b<T[i].t[j].mid()+1) query(i,Left(j),b); else if(b>T[i].t[j].mid()) query(i,Right(j),b); } void Query(int i,int a,int b){//(1, a,b ) query(i,1,b); if(a==T[i].a&&T[i].b==a)return; if(a<T[i].mid()+1) Query(Left(i),a,b); else if(a>T[i].mid()) Query(Right(i),a,b); } void Update(int i,int j,int a,int b){ if(a==T[i].t[j].a&&T[i].t[j].b==b) T[i].t[j].ad^=1; else if(b<T[i].t[j].mid()+1) Update(i,Left(j),a,b); else if(a>T[i].t[j].mid()) Update(i,Right(j),a,b); else{ Update(i,Left(j),a,T[i].t[j].mid()); Update(i,Right(j),T[i].t[j].mid()+1,b); } } void UpDate(int i,int a,int b,int c,int d){//(1, a,b, c,d, ad)在树i中的abcd区间取反 if(a==T[i].a&&T[i].b==b) Update(i,1,c,d); else if(b<T[i].mid()+1) UpDate(Left(i),a,b,c,d); else if(a>T[i].mid()) UpDate(Right(i),a,b,c,d); else{ UpDate(Left(i),a,T[i].mid(),c,d); UpDate(Right(i),T[i].mid()+1,b,c,d); } } int NUM,FLAG; //输入优化 #define DIG(a) (((a)>='0')&&((a)<='9')) #define cini(j) { \ j=FLAG=0; NUM=getchar(); \ while(!DIG(NUM)&&NUM!='-')NUM=getchar(); \ if(NUM=='-'){FLAG=1;NUM=getchar();} \ j=NUM-'0';NUM=getchar(); \ while(DIG(NUM)){j=10*j+(NUM-'0');NUM=getchar();} \ if(FLAG)j=-j; \ } int main() { int xx,n,tt, a,b,c,d; char ch; cin>>xx; while(xx--){ cin>>n>>tt; MakeTree(1,1,n,1,n); while(tt--){ cin>>ch; if(ch=='C'){ cini(a);cini(c);cini(b);cini(d); //cin>>a>>c>>b>>d; UpDate(1,a,b,c,d); } else{ cini(a);cini(b); //cin>>a>>b; flag=0; Query(1,a,b); cout<<flag<<endl; } } cout<<endl; } return 0; }
poj 2299 求逆序数 存储区间内已有的元素个数,每更新一个新数字i,先累加区间 i+1,maxn然后包含i的区间+1
#define Left(i) (i<<1) #define Right(i) (i<<1|1) #define Mid(i) ((T[i].a+T[i].b)>>1) #define MaxN 1000010 #define MAXN 2000100 long long cnt; int arr[MaxN]; struct Node{ int a,b; //区间 long long sum,ad; //区间总和 单个元素增量 }T[MAXN]; void MakeTree(int a,int b,int i){//(1,MAXN,1) T[i].a=a; T[i].b=b; T[i].sum=T[i].ad=0; if(a<b){ MakeTree(a,Mid(i),Left(i)); MakeTree(Mid(i)+1,b,Right(i)); } } void Fen(int i){ if(T[i].a==T[i].b){ T[i].sum+=T[i].ad; T[i].ad=0; } else{ T[Left(i)].ad+=T[i].ad; T[Right(i)].ad+=T[i].ad; T[i].sum+=(T[i].b-T[i].a+1)*T[i].ad; T[i].ad=0; } } long long Query(int i,int c,int d){//区间cd的sum值之和 Fen(i); long long temp=0; if(c==T[i].a&&T[i].b==d) { temp += T[i].sum; } else if(d<Mid(i)+1) { //cd仅在左子树 temp += Query(Left(i),c,d); } else if(c>Mid(i)){ //cd仅在右子树 temp += Query(Right(i),c,d); } else { //cd跨越左右子树 temp += Query(Left(i),c,Mid(i)); temp += Query(Right(i),Mid(i)+1,d); } return temp; } long long Insert(int i,int c,int d,int odd){//在树i中的cd区间增odd long long temp=0; if(c==T[i].a&&T[i].b==d){ T[i].ad+=odd; return (d-c+1)*odd; } if(d<Mid(i)+1){ //cd仅在左子树 temp=Insert(Left(i),c,d,odd); } else if(c>Mid(i)){ //cd仅在右子树 temp=Insert(Right(i),c,d,odd); } else{ //cd跨越左右子树 temp+=Insert(Left(i),c,Mid(i),odd); temp+=Insert(Right(i),Mid(i)+1,d,odd); } T[i].sum+=temp; return temp; } int n,j; void solve(){ for(int i=1;i<=n;i++){ if(arr[i]!=j) cnt+=Query(1,arr[i]+1,j); Insert(1,arr[i],arr[i],1); } cout<<cnt<<endl; } int NUM,FLAG; #define DIG(a) (((a)>='0')&&((a)<='9')) #define cini(j) { \ j=FLAG=0; NUM=getchar(); \ while(!DIG(NUM)&&NUM!='-')NUM=getchar(); \ if(NUM=='-'){FLAG=1;NUM=getchar();} \ j=NUM-'0';NUM=getchar(); \ while(DIG(NUM)){j=10*j+(NUM-'0');NUM=getchar();} \ if(FLAG)j=-j; \ } struct nod{ int num,id; }B[MaxN]; bool cmp(nod n1,nod n2){return n1.num<n2.num;} void readData(){ B[0].num=-1;B[0].id=0; cnt=0; for(int i=1;i<=n;i++) {cini(B[i].num);B[i].id=i;} sort(B+1,B+n+1,cmp); j=0; for(int i=1;i<=n;i++){ if(B[i].num!=B[i-1].num)j++; arr[B[i].id]=j; } } int main() { while(cin>>n&&n){ readData(); MakeTree(1,j,1); solve(); } return 0; }
poj 2528 在墙上贴海报,可以互相覆盖,问最后可以看见几张海报
普通离散化的缺陷:
例一: 1-10 1-4 5-10
例二: 1-10 1-4 6-10
离散化后都变成了[1,4] [1,2] [3,4]
线段2覆盖了[1,2], 线段3覆盖了[3,4], 那么线段1是否被完全覆盖掉了呢?
例一是完全被覆盖掉了, 而例二没有被覆盖
解决办法:
25、26本身相邻,离散为1、2
25、30本身不相邻,中间加一个数,离散为1、3
#define lson i<<1,a,m #define rson i<<1|1,m+1,b #define MaxN 40005 struct Node{ int color; bool lazy; }T[MaxN<<2]; void MakeTree(int i,int a,int b){//(1,a,b) T[i].color=T[i].lazy=0; if(a<b){ int m=(a+b)>>1; MakeTree(lson); MakeTree(rson); } else{} } void PushDown(int i){ T[i<<1].lazy=T[i<<1|1].lazy=1; T[i].lazy=0; T[i<<1].color=T[i<<1|1].color=T[i].color; } void UpDate(int i,int a,int b,int c,int d,int val){//(1,1,n,c,d,val) if(a==c&&b==d){ T[i].color=val;T[i].lazy=1;return; } int m=(a+b)>>1; if(T[i].lazy&&a<b)PushDown(i); if(d<=m){ UpDate(lson,c,d,val); } else if(c>=m+1){ UpDate(rson,c,d,val); } else{ UpDate(lson,c,m,val); UpDate(rson,m+1,d,val); } } int cnt; bool bo[10005]; void Query(int i,int a,int b,int c,int d){ int m=(a+b)>>1; if(T[i].lazy){ int t=T[i].color; if(t&&!bo[t]){ bo[t]=1; cnt++; } return; } if(a==b)return; Query(lson,c,m); Query(rson,m+1,d); } struct No{ int num,id; }no[20005]; bool cmp(No n1,No n2){ return n1.num<n2.num; } int nn[20005]; int n,abc; void LiSan(){//ÀëÉ¢»¯ cini(n); memset(no,0,sizeof(no)); int i; for(i=1;i<=n;i++){ cini(no[2*i].num); no[2*i].id=2*i; cini(no[2*i+1].num);no[2*i+1].id=2*i+1; } sort(no+2,no+2*i,cmp); no[1].num=-1; abc=0; for(int i=2;i<=2*n+1;i++){ if(no[i-1].num!=no[i].num){ if(no[i-1].num+1==no[i].num)abc++; else abc+=2; } nn[no[i].id]=abc; } } int main() { int c; cini(c); while(c--){ LiSan(); MakeTree(1,1,abc); memset(bo,0,sizeof(bo)); int col=0; for(int i=1;i<=n;i++){ col++; UpDate(1,1,abc,nn[2*i],nn[2*i+1],col); } cnt=0; Query(1,1,abc,1,abc); cout<<cnt<<endl; } return 0; }
poj 2828 人们一个一个的来排队并插队,按人到来的顺序给出每个人插队的位置(插在第几个人后面),并告知每个人的id号,输出最终队伍的情况。
从最后来的一个人开始向来的更早的人遍历,这样pos(插在第几个人后面)的意义就变成了,前面有多少个空位。线段树上每个节点中存储的是当前时刻,该区间有多少空位。
struct Node{ int num; }T[MaxN<<2]; void MakeTree(int i,int a,int b){//(1,a,b) T[i].num=b-a+1; if(a<b){ int m=(a+b)>>1; MakeTree(lson); MakeTree(rson); } } int x[MaxN],y[MaxN],z[MaxN],val; void UpDate(int i,int a,int b,int c){//寻找第c个空位 T[i].num--; int m=(a+b)>>1; if(a==b) z[a]=val; else if(c>T[i<<1].num)UpDate(rson,c-T[i<<1].num); else UpDate(lson,c); } int main() { int n; while(cin>>n){ MakeTree(1,1,n); for(int i=1;i<=n;i++){ cini(x[i]);cini(y[i]); } for(int i=n;i>=1;i--){ val=y[i]; UpDate(1,1,n,x[i]+1); } for(int i=1;i<=n;i++) printf("%d ",z[i]); cout<<endl; } return 0; }
poj 2886
N 个小孩围成一圈,顺时针编号为 1 到 N。每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的,则是右手边的第 -A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。
打表求反素数,根据反素数求第几个离开得到糖果最多
线段树存储区间内剩下的人数,
若k>lson.sum 则到右子树中找第k-lson.sum个人
否则在左子树中找第k个人
#define lson i<<1,a,m #define rson i<<1|1,m+1,b #define MaxN 500010 struct Node{ int sum; }T[MaxN<<2]; int n,k; inline void MakeTree(int i,int a,int b){//(1,a,b) T[i].sum=b-a+1; if(a<b){ int m=(a+b)>>1; MakeTree(lson); MakeTree(rson); } } inline int UpDate(int i,int a,int b,int t){//(1,1,n,c,d,val) T[i].sum--; if(a==b) return a; int m=(a+b)>>1; if(t>T[i<<1].sum)return UpDate(rson,t-T[i<<1].sum); else return UpDate(lson,t); } /* int Query(int i,int a,int b,int c,int d){ if(a==c&&b==d) { return T[i].sum; } int temp=0,m=(a+b)>>1; if(d<=m) { temp=Query(lson,c,d); } else if(c>=m+1){ temp=Query(rson,c,d); } else { temp+=Query(lson,c,m); temp+=Query(rson,m+1,d); } return temp; }*/ /*int db[MaxN],p[MaxN];//db[i]:i的因子数 p[i]: db[1]~db[i]最大者的下标 void dabiao(){ for(int i=1;i<=MaxN;i++) for(int j=i;j<=MaxN;j+=i) db[j]++; int pos=0,val=0; for(int i=1;i<=MaxN;i++){ if(db[i]>val){val=db[i];pos=i;} p[i]=pos; } }*/ const int antiprime[] = {1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160, 25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280}; const int factorNum[] = {1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72, 80,84,90,96,100,108,120,128,144,160,168,180,192,200,216,224}; char name[MaxN][11]; int card[MaxN]; void readData(){ //scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ //scanf("%s",name[i]); //cini(card[i]); scanf("%s%d",name[i],&card[i]); } } void solve(){ //cout<<"A"<<endl; int p=0; while(antiprime[p++]<=n); p-=2; int u=antiprime[p],pos,mod=n,t=0; for(int i=1;i<=u;i++){ if(t>0) k=(k+t-2)%mod+1; else k = ((k+t-1)%mod+mod)%mod+1; pos=UpDate(1,1,n,k); mod--; t =card[pos]; //if(mod==0)break; } printf("%s %d\n",name[pos],factorNum[p]); /* while(times--){ //int t=(Lnum+k-1)%T[1].sum+1; //cout<<"k="<<k<<' '<<T[1].sum<<endl;; //if(T[1].sum<=1)break; if(k>0)k=(k-1)%T[1].sum+1; else { k=(k+1)%T[1].sum-1; //cout<<k<<endl; k=k+T[1].sum+1; } int t=Lnum+k; if(t>T[1].sum)t-=T[1].sum; pos=UpDate(1,1,n,t); Lnum=Query(1,1,n,1,pos); k=card[pos]; //cout<<name[pos]<<' '<<t<<' '<<Lnum<<endl; } */ //cout<<" "<<c<<" "; //cout<<name[pos]<<' '<<db[u]<<endl; } int main() { //dabiao(); while(scanf("%d%d",&n,&k)!=EOF){ readData(); MakeTree(1,1,n); solve(); } return 0; }
poj 3667
输入a, b, c
a==1, 输出最左边的连续b个0的起始位置, 并将b个0置为1
a==2, b开始的连续c个元素置为0
分析:
记录 左边连续0的个数,右边连续0的个数,最大0的个数
#define lson i<<1,a,m #define rson i<<1|1,m+1,b #define MaxN 50005 int n; struct Node{ int l,r,ma;//左边空房间数 右边空房间数 最大空房间数 bool lazy,f; }T[MaxN<<2]; void MakeTree(int i,int a,int b){//(1,a,b) T[i].l=T[i].r=T[i].ma=b-a+1; T[i].f=T[i].lazy=0; if(a<b){ int m=(a+b)>>1; MakeTree(lson); MakeTree(rson); } } inline int Max(int a,int b){return a>b?a:b;} void PushDown(int i,int a,int b){ int m=(a+b)>>1; T[i].lazy=0; if(a<b){ T[i<<1].lazy=T[i<<1|1].lazy=1; if(T[i].f==0){ T[i<<1].f=T[i<<1|1].f=0; T[i<<1].l=T[i<<1].r=T[i<<1].ma=m-a+1; T[i<<1|1].l=T[i<<1|1].r=T[i<<1|1].ma=b-m; } else{ T[i<<1].f=T[i<<1|1].f=1; T[i<<1].l=T[i<<1].r=T[i<<1].ma=0; T[i<<1|1].l=T[i<<1|1].r=T[i<<1|1].ma=0; } } } void PushUp(int i,int a,int b){ int m=(a+b)>>1; T[i].l=T[i<<1].l; if(T[i<<1].l==m-a+1)T[i].l+=T[i<<1|1].l; T[i].r=T[i<<1|1].r; if(T[i<<1|1].r==b-m)T[i].r+=T[i<<1].r; T[i].ma=Max(T[i<<1].ma,T[i<<1|1].ma); T[i].ma=Max(T[i].ma,T[i<<1].r+T[i<<1|1].l); } void Delete(int i,int a,int b,int c,int d){//删除 if(a==c&&b==d){ T[i].lazy=1; T[i].f=0; T[i].l=T[i].r=T[i].ma=b-a+1; return; } if(T[i].lazy)PushDown(i,a,b); int m=(a+b)>>1; if(d<=m) Delete(lson,c,d); else if(c>=m+1) Delete(rson,c,d); else{ Delete(lson,c,m); Delete(rson,m+1,d); } if(a<b)PushUp(i,a,b); } int Insert(int i,int a,int b,int c,bool v){//v为真 则在最左边找连续的c个空房间 否则在最右边找 int m=(a+b)>>1,ans=0; if(b-a+1==c){ T[i].lazy=1;T[i].f=1; T[i].l=T[i].r=T[i].ma=0; return a; } if(T[i].lazy)PushDown(i,a,b); if(v){//先左 再中 后右 if(T[i<<1].ma>=c) ans= Insert(lson,c,true); else if(T[i<<1].r&&T[i<<1|1].l&&T[i<<1].r+T[i<<1|1].l>=c){ int temp=T[i<<1].r; ans=Insert(lson,temp,false); Insert(rson,c-temp,true);// } else if(T[i<<1|1].ma>=c) ans=Insert(rson,c,true); } else{//先右 再中 后左 if(T[i<<1|1].ma>=c) ans= Insert(rson,c,false); else if(T[i<<1].r&&T[i<<1|1].l&&T[i<<1].r+T[i<<1|1].l>=c){ int temp=T[i<<1|1].l; ans=Insert(lson,c-temp,false); Insert(rson,temp,true); } else if(T[i<<1].ma>=c) ans=Insert(lson,c,false); } if(a<b)PushUp(i,a,b); return ans; } int main() { int p; cini(n);cini(p); MakeTree(1,1,n); int c,i,m; while(p--){ cini(c); if(c==1){ cini(i); cout<<Insert(1,1,n,i,true)<<endl; } else if(c==2){ cini(i);cini(m); Delete(1,1,n,i,i+m-1); } } return 0; }