1.支持以下操作:
A.对一个区间求最大值。
B.对一个区间的所有数&上一个数。
C.对一个区间的所有数|上一个数。
直接线段树维护。在修改的时候,如果继续修改没有意义,则打上标记。这也就意味着,我们需要维护当前区间上所有数字的某一个二进制位上的数是否相同,以及是多少。
打标记时,可以直接对另一个标记修改。
复杂度为nlog^2n,可以考虑势能分析。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2E5+5; 4 const int mask=(1<<21)-1; 5 int n,m,a[maxn]; 6 int t[maxn*4],tagA[maxn*4],tagB[maxn*4]; 7 int what[maxn*4],can[maxn*4]; 8 bool leaf[maxn*4]; 9 inline int read() 10 { 11 char ch=getchar(); 12 while(!isdigit(ch))ch=getchar(); 13 int sum=ch-'0';ch=getchar(); 14 while(isdigit(ch)){sum=sum*10+ch-'0';ch=getchar();} 15 return sum; 16 } 17 int G[55]; 18 inline void write(int x) 19 { 20 int g=0; 21 do{G[++g]=x%10;x/=10;}while(x); 22 for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar(' '); 23 } 24 inline void pushup(int num) 25 { 26 if(leaf[num]) 27 return; 28 int l=num<<1,r=num<<1|1; 29 can[num]=(can[l]&can[r])&(mask^(what[l]^what[r])); 30 what[num]=what[l]; 31 t[num]=max(t[l],t[r]); 32 } 33 void build(int l,int r,int num) 34 { 35 tagA[num]=mask; 36 if(l==r) 37 { 38 t[num]=a[l]; 39 can[num]=mask; 40 what[num]=t[num]; 41 leaf[num]=1; 42 return; 43 } 44 int mid=(l+r)>>1; 45 build(l,mid,num<<1),build(mid+1,r,num<<1|1); 46 pushup(num); 47 } 48 inline void updateA(int num,int x) 49 { 50 what[num]&=(mask^can[num])|(can[num]&x); 51 } 52 inline void pushdownA(int num) 53 { 54 if(tagA[num]==mask) 55 return; 56 int x=tagA[num]; 57 tagA[num]=mask; 58 t[num]&=x; 59 updateA(num,x); 60 if(leaf[num]) 61 return; 62 tagA[num<<1]&=x; 63 tagB[num<<1]&=x; 64 t[num<<1]&=x; 65 updateA(num<<1,x); 66 tagA[num<<1|1]&=x; 67 tagB[num<<1|1]&=x; 68 t[num<<1|1]&=x; 69 updateA(num<<1|1,x); 70 } 71 inline void updateB(int num,int x) 72 { 73 what[num]|=can[num]&x; 74 } 75 inline void pushdownB(int num) 76 { 77 if(tagB[num]==0) 78 return; 79 int x=tagB[num]; 80 tagB[num]=0; 81 t[num]|=x; 82 updateB(num,x); 83 if(leaf[num]) 84 return; 85 tagB[num<<1]|=x; 86 tagA[num<<1]|=x; 87 t[num<<1]|=x; 88 updateB(num<<1,x); 89 tagB[num<<1|1]|=x; 90 tagA[num<<1|1]|=x; 91 t[num<<1|1]|=x; 92 updateB(num<<1|1,x); 93 } 94 inline void pushdown(int num) 95 { 96 pushdownB(num),pushdownA(num); 97 } 98 void changeA(int l,int r,int L,int R,int x,int num) 99 { 100 pushdown(num); 101 if(L<=l&&r<=R) 102 { 103 int g=0; 104 bool flag=1; 105 g|=can[num]&x; 106 g|=mask^can[num]; 107 if((mask^can[num])&(mask^x)) 108 flag=0; 109 tagA[num]&=g; 110 if(l==r) 111 { 112 t[num]&=x; 113 pushdown(num); 114 can[num]=mask; 115 what[num]=t[num]; 116 return; 117 } 118 if(flag) 119 { 120 pushdown(num); 121 pushup(num); 122 return; 123 } 124 } 125 pushdown(num); 126 int mid=(l+r)>>1; 127 if(R<=mid) 128 changeA(l,mid,L,R,x,num<<1); 129 else if(mid<L) 130 changeA(mid+1,r,L,R,x,num<<1|1); 131 else 132 changeA(l,mid,L,R,x,num<<1),changeA(mid+1,r,L,R,x,num<<1|1); 133 pushup(num); 134 } 135 void changeB(int l,int r,int L,int R,int x,int num) 136 { 137 pushdown(num); 138 if(L<=l&&r<=R) 139 { 140 tagB[num]|=can[num]&x; 141 x&=mask^can[num]; 142 if(l==r) 143 { 144 t[num]|=x; 145 pushdown(num); 146 can[num]=mask; 147 what[num]=t[num]; 148 return; 149 } 150 } 151 if(x==0) 152 { 153 pushdown(num); 154 pushup(num); 155 return; 156 } 157 pushdown(num); 158 int mid=(l+r)>>1; 159 if(R<=mid) 160 changeB(l,mid,L,R,x,num<<1); 161 else if(mid<L) 162 changeB(mid+1,r,L,R,x,num<<1|1); 163 else 164 changeB(l,mid,L,R,x,num<<1),changeB(mid+1,r,L,R,x,num<<1|1); 165 pushup(num); 166 } 167 int ask(int l,int r,int L,int R,int num) 168 { 169 pushdown(num); 170 if(L<=l&&r<=R) 171 { 172 pushup(num); 173 return t[num]; 174 } 175 int mid=(l+r)>>1,ans=0; 176 if(R<=mid) 177 ans=ask(l,mid,L,R,num<<1); 178 else if(mid<L) 179 ans=ask(mid+1,r,L,R,num<<1|1); 180 else 181 ans=max(ask(l,mid,L,R,num<<1),ask(mid+1,r,L,R,num<<1|1)); 182 pushup(num); 183 return ans; 184 } 185 int main() 186 { 187 freopen("a.in","r",stdin); 188 freopen("a.out","w",stdout); 189 ios::sync_with_stdio(false); 190 n=read(),m=read(); 191 for(int i=1;i<=n;++i) 192 a[i]=read(); 193 build(1,n,1); 194 while(m--) 195 { 196 int opt=read(),l=read(),r=read(),x; 197 if(l>r) 198 swap(l,r); 199 if(opt==3) 200 write(ask(1,n,l,r,1)); 201 else 202 { 203 x=read(); 204 if(opt==1) 205 changeA(1,n,l,r,x,1); 206 else 207 changeB(1,n,l,r,x,1); 208 } 209 } 210 return 0; 211 }
2.爱丽丝和鲍勃在树上进行博弈游戏。轮流操作,每次将一个点涂成自己所对应的颜色,不能不涂。最后,他们都希望自己的连通块数减去对方的连通块数最大,问最优策略是什么?
考虑涂完颜色后的数。不妨设爱丽丝的颜色为A,鲍勃的颜色为B。对于一个A节点,若有k个A节点相连,相当于连通块数少了k;若有k个B节点相连,如果把这个点涂成B,能够让对方减少k个连通块。也就是说,谁涂了度数越大的点,谁就更不利。
因此最优策略为将度数从小到大排序,依次选取(没有顺序之分)。
3.现实版方格数树!你站在原点处,在(0,n-1)*(n-1,0)的正方形中,每个整点上都有一颗半径为r的树。问你能看到多少树?(能看到当且仅当存在一条过原点的直线,与圆有交点,且与前面的其他圆没有任何交点)。n<=1E9,r的精确到小数点后6位。
对于(x,y),若x和y不互质,则一定看不到。
若(x,y)互质,能看到当且仅当$x^2+y^2<frac{1}{r^2}$。
容斥即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<cstdlib> 7 #include<algorithm> 8 #define N 1000000 9 using namespace std; 10 typedef long long ll; 11 typedef long double ld; 12 ld M; 13 int n,r,mu[1000010],pri[1000010],tot,ans; 14 bool flag[1000010]; 15 inline ll f(ld M,int n) 16 { 17 ll ans=0; 18 int t=(int)sqrt(M); 19 for(int B=1;B<=t && B<=n;B++) 20 ans+=min((ll)n,(ll)(ceil(sqrt(M-1ll*B*B))-1)); 21 return ans; 22 } 23 int main() 24 { 25 freopen("b.in","r",stdin); 26 freopen("b.out","w",stdout); 27 cin>>n>>r; 28 M=1e12/r/r; 29 mu[1]=1; 30 n--; 31 for(int i=2;i<=N;i++) 32 { 33 if(flag[i]==0) pri[++tot]=i,mu[i]=-1; 34 for(int j=1;j<=tot && 1ll*i*pri[j]<=N;j++) 35 { 36 flag[i*pri[j]]=1; 37 if(i%pri[j]==0){mu[i*pri[j]]=0; break;} 38 else mu[i*pri[j]]=-mu[i]; 39 } 40 } 41 ll ans=0; 42 for(int i=1;i<=N;i++) 43 if(mu[i]!=0) ans+=mu[i]*f(M/i/i,n/i); 44 cout<<ans+2<<endl; 45 return 0; 46 }