T1:AC
solution:
用樹狀數組維護前綴和,修改時暴力,用一個並查集維護當前點之後第一個不爲0或1的點是誰。。每次修改之後路徑壓縮一下並查集。
#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10;
long long ans[maxn],num[maxn],n,m;
void add(long long k,long long left,long long right){//to make a tree
if(left==right){
ans[k]=num[left];
return ;
}
long long mid=(left+right)>>1;
add(k*2,left,mid);
add(k*2+1,mid+1,right);
ans[k]=ans[k*2]+ans[k*2+1];
}
long long query(int k,int lt,int rt,int qx,int qy){
if(qx>rt||qy<lt)
return 0;
else{
if(qx<=lt&&qy>=rt)
return ans[k];
}
long long mid=(lt+rt)>>1;
return query(k*2,lt,mid,qx,qy)+query(k*2+1,mid+1,rt,qx,qy);
}
void line(long long k,long long lt,long long rt,long long qx,long long qy){
if(ans[k]==rt-lt+1)//if lt-rt are full of 1,sqrt(1)=1,so it's ennesessary to continue(that's a very important branch-cutting)
return ;
if(qy<lt||qx>rt)
return ;
else if(lt>=qx&&rt<=qy&<==rt){
ans[k]=sqrt(ans[k]);//change
return ;
}
else{
long long mid=(lt+rt)/2;
line(k*2,lt,mid,qx,qy);
line(k*2+1,mid+1,rt,qx,qy);
ans[k]=ans[k*2]+ans[k*2+1];
return ;
}
}
int main(){
//freopen("game.in","r",stdin);
//freopen("game.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&num[i]);
//cin>>num[i];
add(1,1,n);
cin>>m;
for(int i=1;i<=m;i++){
long long k,x,y;
scanf("%lld%lld%lld",&k,&x,&y);
if(k==0)
line(1,1,n,x,y);
else
printf("%lld\n",query(1,1,n,x,y));
}
return 0;
}
T2:WA
reason:Because the meaning of the question is to add the numbers into fewer groups,so I used kruskal to get some points…(only 80 points)
solution:
首先floyd傳遞閉包,求出兩兩點之間的轉移人員的代價。。然後枚舉出和爲0的飽和的選點集合。。。狀壓DP就行了。
T3:AC
sol