[caioj 樹狀陣列2(破壞公路)]---樹狀陣列
題目描述:
在太平洋中心有一個圓形小島,沿著小島的海岸線分佈著n個小鎮,編號分別為1,2,3~~n;小鎮i-1、小鎮i、小鎮i+1是相鄰的(當然小鎮n與小鎮1相鄰)。相鄰小鎮之間存在一條公路,公路也有編號,公路i連線小鎮i和小鎮i+1,公路n連線小鎮n和小鎮1.現在對小島有m個操作,操作有兩種:
詢問操作:1 x y 代表小鎮x到小鎮y是否聯通,聯通輸出1,否則輸出0
修改操作:0 x 代表修改公路x,如果公路原來是完好的,則斷開,否則修好公路x。
輸入格式:
輸入第一行為一個整數t,代表下來有t組資料
每組資料輸入第一行包含兩個整數n,m,分別表示小鎮個數和操作命令數目。
輸入接下來的m行,每一行代表一條操作指令。
輸出格式:
對於相鄰兩組資料之間要留一空行。
輸入樣例:
1
5 10
1 2 5
0 4
1 4 5
0 2
1 3 4
1 1 3
0 1
0 2
1 2 4
1 2 5
輸出樣例:
1
1
1
0
1
0
資料規模:
對於20%的資料滿足:1 < = n, m <=1000。
對於40%的資料滿足:1 < = n, m <= 100000。
對於100%的資料滿足:1 < = n, m <= 500000。
分析
坑爹的輸出QAQ 如圖所示:
前者是編號,後者是值(道路的狀態 0:聯通 1:斷開)
按題意,其實就是求一段道路的區間和( 但又有些不同,如第二次輸出,4->5被封,但可以反向4->3->2->1->5 )
SO,直接用樹狀陣列求區間和(s),與 sum(總和)-s的值,若 二者其一為0,則聯通
程式碼
各種卡常
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;
int n,m;
int a[500005],b[500005];
inline int read()
{
int k=1;
int sum=0;
char c=getchar();
for(;'0'>c || c>'9' ;c=getchar())
if(c=='-') k=-1;
for(;'0'<=c && c<='9';c=getchar())
sum=sum*10 +c-'0';
return sum*k;
}
inline void write(int x)
{
if(x<0) { putchar('-'); x*=-1; }
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int abs(int x)
{
return x>0?x:-x;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void updata(int x,int y)
{
for(;x<=n;x+=lowbit(x))
b[x]+=y;
}
inline int getsum(int x)
{
int sum=0;
for(;x;x-=lowbit(x))
sum+=b[x];
return sum;
}
int main()
{
open("1098");
int T=read();
for(;T;--T)
{
n=read(); m=read();
int sum=0;
for(int i=1;i<=m;++i)
{
int f=read();
if(f)
{
int x=abs(getsum(read()-1)-getsum(read()-1));
//注意取絕對值(順序問題);
//-1不好解釋,看圖分析(第i條道路連線i與i+1的點);
//至於read()-1==0的情況,可看樣例,不用特殊處理
write((x&&(sum-x))?0:1);
putchar('\n');
}
else
{
int x=read();
updata(x,a[x]?-1:1);
//printf("%d %d\n",x,a[x]?-1:1);
if(a[x]) --sum; else ++sum;
a[x]^=1;
}
}
putchar('\n');
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
}
close;
return 0;
}
關於caioj
哪位dalao可解釋一下為何caioj有些題用讀優會TLE 無力