B - Stone Age Problem
一个操作是将a[i]换成x,另一个操作是都换成x,每次操作都要输出数组的和;
这题的麻烦点就在于第二个操作,这里我们可以用一下线段树的tag思想,也不完全像tag,只能说类似吧,设一个vis数组表示元素i进行过多少次第二种操作,cnt表示到目前为止进行了多少次操作,last表示上一个第二操作的x,如果vis[i]<cnt且要进行第一个操作了,说明元素i要先进行更新在操作,更新也就是sum=sum-last+x,因为元素i被更新成last了,然后操作完后元素i又被更新成了x,且vis[i]=cnt表示该需要进行的第二个操作都进行完了,如果vis[i]==cnt且要进行第二个操作,那就没有必要鸟这些东西了,直接sum=sum-a[i]+x,a[i]=x;就可以;当进行操作2时,就需要更新,cnt++,sum=x*n,last=x;
#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=1e8;
ll n,q,a[200005],sum,vis[200005];
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&q);
sum=0;
ll cnt=0,last=0;
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
while(q--){
ll t,i,x;
scanf("%lld",&t);
if(t==1){
scanf("%lld%lld",&i,&x);
if(vis[i]<cnt){
sum=sum-last+x;
vis[i]=cnt;
a[i]=x;
}
else{
sum=sum-a[i]+x;
a[i]=x;
}
printf("%lld\n",sum);
}
else{
scanf("%lld",&x);
cnt++; last=x;
sum=x*n;
printf("%lld\n",sum);
}
}
return 0;
}
C - Rooks Defenders
row[i]表示第i行车的数量,col[i]表示第i列车的数量,t1维护行的前缀和,t2维护列的前缀和,t1,t2为树状数组,查询的时候只要每行都满足至少有一个车或每列都满足至少有一个车就可以,放车的时候如果row[x]=1,就不需要修改t1了,反之需要修改,但无论修不修改都要row[x]++,col同理,删除的时候先让row[x]--,col[y]--,如果row[x]<=0才去修改,col同理,这样是为了保证查询前缀和的时候保证每行只有一个方便查询;
#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=1e8;
ll n,q,t1[100005],t2[100005],row[100005],col[100005];
void add(ll flag,ll x,ll y){
for(int i=x;i<=n;i+=lowbit(i))
if(flag) t1[i]+=y;
else t2[i]+=y;
}
ll ask(ll flag,ll x){
ll res=0;
for(int i=x;i;i-=lowbit(i))
if(flag) res+=t1[i];
else res+=t2[i];
return res;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&q);
while(q--){
ll t,x,y,x1,y1;
scanf("%lld",&t);
if(t==1){
scanf("%lld%lld",&x,&y);
if(row[x]<1) add(1,x,1);
if(col[y]<1) add(0,y,1);
row[x]++;col[y]++;
}
else if(t==2){
scanf("%lld%lld",&x,&y);
row[x]--;col[y]--;
if(row[x]<1) add(1,x,-1);
if(col[y]<1) add(0,y,-1);
}
else{
scanf("%lld%lld%lld%lld",&x,&y,&x1,&y1);
// cout<<ask(1,x1)-ask(1,x-1)<<" ss "<<ask(0,y1)-ask(0,y-1)<<endl;
if(ask(1,x1)-ask(1,x-1)>=x1-x+1||ask(0,y1)-ask(0,y-1)>=y1-y+1)
printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
pSort - 题目 - Daimayuan Online Judge
可以看出i能和|i-d[i]|,|i+d[i]|的位置互换,如果这两个绝对值都在[1,n]范围内的话,然后又可以发现这些可以可以互换的位置具有传递性,比如a和b可以换,b和c可以换,那a,b,c都可以换,所以只要找出这些连通块,看看b中这些交换的位置是否在一个连通块中就可以了,用并查集更方便;
#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=1e8;
ll n,b[105],d[105],s[105];
ll findd(ll x){
return s[x]=x==s[x]?x:findd(s[x]);
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&b[i]);
s[i]=i;
}
for(int i=1;i<=n;i++){
scanf("%lld",&d[i]);
if(i-d[i]>=1){
ll j=i-d[i];
ll u=findd(i),v=findd(j);
if(u!=v) s[u]=v;
}
if(i+d[i]<=n){
ll j=i+d[i];
ll u=findd(i),v=findd(j);
if(u!=v) s[u]=v;
}
}
for(int i=1;i<=n;i++){
if(findd(b[i])!=findd(i)){
// cout<<findd(b[i])<<" "<<findd(i)<<" "<<i<<" "<<b[i]<<endl;
printf("NO\n");
return 0;
}
}
printf("YES\n");
return 0;
}
Candy Machine
可以看出删掉一个最大值,平均值会下降,那么我一开始全都要,然后从最大值开始删,每次统计有多少个大于平均值的,最后输出一个最大值就可以
#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=1e8;
ll n,a[1000006];
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&n);
ll sum=0,ave=0,ans=0,cnt=0,ma=n;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
sort(a+1,a+n+1);
for(int i=n;i>=1;i--){
ave=sum/i;
while(a[ma]>ave) ma--,cnt++;
ans=max(ans,cnt);
// cout<<cnt<<" "<<i<<endl;
sum-=a[i];
cnt--;
}
printf("%lld\n",ans);
return 0;
}