1. 程式人生 > >[2018.10.23 T2] 行星通道計劃

[2018.10.23 T2] 行星通道計劃

暫無連結

行星通道計劃

【題目描述】

在戰爭勝利後,火星文明已經高度發達。為了更快捷的在行星內轉移物資,人類開始了浩浩蕩蕩的行星通道計劃 。

行星通道計劃要完成的事情是在火星赤道上選擇 n n 個站點(每個站點編號為 1 n

1\sim n n n 個站點按編號依次順時針排列)。用高強度材料製成筆直的管道穿越赤道截面連線兩個站點。這樣就可以利用火星自身引力完成物資在赤道上兩處地表的快速轉移。在這裡,由於火星很大,一條管道可以近似為一根直線,而赤道截面可以看做一個圓。

但是在赤道面內修建通道有一個弊端,新修建的通道會和之前修建的通道相交,這樣需要花費 1

1 的代價銜接兩個相交的通道。

在行星通道計劃開展的這段時間內,你被任命管理行星通道系統。

具體的來說,你需要快速的按照上級的命令組織進行如下操作:

1、在 n n 個站點中將指定的兩個沒有連線的站點連線起來,並查詢此次修建需要花費的代價。

2、拆除一條已有的管道。(可以在下一次 1

1 操作中重新修建)

p.s.保證每次需要連線的兩個站點連線時沒有其他通道經過這兩個站點 。

保證刪除的通道當前存在。

【輸入】

第一行兩個正整數 n , m n,m 分別表示站點數和運算元

接下來 m m 行表示操作:

o p = 0 op=0 時,輸入 x , y ( 1 x , y n ) x,y(1≤x,y≤n) ,表示在編號為 x , y x,y 的站點之間修建管道,並查詢花費的代價。

o p = 1 op=1 時,輸入 x x ,表示刪除第x次操作修築的管道。( x x 次操作包含所有 1 , 2 1,2 的操作)

【輸出】

對於每一個 1 1 操作輸出一行,表示本次修築的代價。

【輸入樣例】

10 7
0 1 7
0 9 2
0 10 5
1 3
0 3 6
0 4 8
0 5 10

【輸出樣例】

0
1
2
0
2
4

【提示】
【樣例解釋】

對於樣例,通道系統每一時刻的狀態如下:

12501.png
12503.png

【資料範圍】

3.png

題解

把一條 x y x\to y 的通道看做平面上的點 ( x , y ) (x,y) ,就能發現每次加入一條邊的代價實際上是一個(或兩個)矩形內的點數,那麼我們就上二維樹狀陣列吧。

出題人還有個很神的題解:
4.png

程式碼

因為出題人的做法如上,導致時限變成了 500 m s 500ms ,所以我們要把二維樹狀陣列開成二維陣列來訪問連續記憶體,封裝結構體會 T L E \mathcal{TLE}

#include<bits/stdc++.h>
#define lb(x) (x&-x)
using namespace std;
const int N=1005;
struct Q{int op,x,y;}e[500005];
int n,m,r,ans,S[N][N];
char c;
int read()
{
    for(r=0;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())r=(r<<1)+(r<<3)+c-'0';
    return r;
}
int que(int x,int y){int r=0;for(int i=x;i;i-=lb(i))for(int j=y;j;j-=lb(j))r+=S[i][j];return r;}
void add(int x,int y,int v){for(int i=x;i<=n;i+=lb(i))for(int j=y;j<=n;j+=lb(j))S[i][j]+=v;}
void in(){n=read(); m=read();}
void ac()
{
	for(int i=1,l,r,fl;i<=m;i++)
	{
		e[i].op=read();
		if(e[i].op==0)
		{
			e[i].x=read();e[i].y=read();
			if(e[i].x>e[i].y) swap(e[i].x,e[i].y);
			l=e[i].x,r=e[i].y;
			printf("%d\n",que(l-1,r-1)-que(l-1,l)+que(r-1,n)-que(r-1,r)-que(l,n)+que(l,r));
			add(l,r,1);
		}	
		else{fl=read();add(e[fl].x,e[fl].y,-1);}
	}
}
int main(){in(),ac();}