題解 CF555C 【Case of Chocolate】
思路:
\(\quad\)說實話,第一眼看這題想到的是線段樹,但無奈 \(1<=n<=10^ 9\) ,離散化有點複雜,動態開點又不會,所以使用了一種離線做法,跑的還賊快(大霧
\(\quad\)現將所有操作存起來, \(dir\) 表示方向, \(1\) 為上, \(0\) 為左,然後按 \(x\) 為第一關鍵字, \(t\) (時間)為第二關鍵字排序(我第一次 \(WA\) 就是這個原因)
struct node{ int x,y,t,dir; }a[N],b[N]; il bool cmp(node a1,node a2){return a1.x==a2.x?a1.t<a2.t:a1.x<a2.x;} for(re i=1,x,y;i<=m;i++) { x=read(),y=read();ch=getchar(); if(ch=='U')a[i]=(node){x,y,i,1}; else a[i]=(node){x,y,i,0}; } sort(a+1,a+m+1,cmp);
\(\quad\)然後考慮每一種情況,顯然,向左的操作會被前面的向上的操作影響(前面的指 \(x\) 小於 \(TA\) ,且時間 \(t\) 也小於 \(TA\) 的),向上的操作會被後面的向左的操作影響(後面指 \(x\) 大於 \(TA\) ,但時間 \(t\) 小於 \(TA\) 的),所以可以發現相鄰的向上的操作和向左的操作會互相影響(相鄰是指x相鄰),這時候我們就要判斷它們的時間先後了。
\(\quad\)然後我們就可以發現只有向上的操作在前,才有可能對後面的向左的操作產生影響(先不考慮時間),另外向上的也只被後面的第一個向左的所影響,所以向上的暫時無法得出答案,先放進一個棧中儲存,只有遇到向左的就把棧中的時間大於 \(TA\)
\(\quad\)現在來模擬一個數據來理解一下。
\(\quad\)先排序,對於操作 \(4\) ,此時棧是空的,直接更新答案,對於操作 \(6\) 、操作 \(1\) 和操作 \(5\) ,直接存進棧裡,等到操作 \(3\) 時開始退棧,先比較棧頂的時間,更新操作 \(5\) 的時間,將 \(5\) 退出,然後和操作 \(1\) 比較,停止退棧,更新操作 \(3\) 本身的答案,最後將操作 \(2\) 壓進棧中,迴圈結束,將棧中元素全部退出,這些把一列的巧克力都吃光了。
\(\quad\)如果還不理解就看看完整程式碼吧,附帶註釋。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define re register int
#define int long long
#define il inline
il int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
il void print(int x)
{
if(x<0)putchar('-'),x=-x;
if(x/10)print(x/10);
putchar(x%10+'0');
}
const int N=2e5+5;
int n,m,ans[N],tot;
struct node{
int x,y,t,dir;
}a[N],b[N];
il bool cmp(node a1,node a2){return a1.x==a2.x?a1.t<a2.t:a1.x<a2.x;}//注意
signed main()
{
n=read();m=read();char ch;
for(re i=1,x,y;i<=m;i++)
{
x=read(),y=read();ch=getchar();
if(ch=='U')a[i]=(node){x,y,i,1};//dir=1表示向上,Up
else a[i]=(node){x,y,i,0};//dir=0表示向左,Left
}
sort(a+1,a+m+1,cmp);//排序
b[0]=(node){0,n+1,0,1};//處理邊界
for(re i=1;i<=m;i++)
{
if(a[i].x==a[i-1].x&&a[i].y==a[i-1].y)continue;//如果遇到相同的就跳過,後面的一個巧克力都吃不到
if(a[i].dir)b[++tot]=a[i];
else {
while(b[tot].t>a[i].t){//條件:時間更大
ans[b[tot].t]=b[tot].y-a[i].y;//更新答案
tot--;//退棧
}
ans[a[i].t]=a[i].x-b[tot].x;//不能再退棧時,更新自己的答案
}
}
while(tot){
ans[b[tot].t]=b[tot].y;//將還在棧裡的退出來
tot--;
}
for(re i=1;i<=m;i++)print(ans[i]),putchar('\n');
return 0;
}