P3635 [APIO2012] 苦无

题意

一个 \(W\times H\) 的平面,有 \(n\) 个点,每个点有一个方向,每个时刻点会向祂的方向移动一个方向移动一个单位,两个点相遇时会消失。平面内被点经过的格子数量。
\(H,W\le10^9,n\le10^5\)

思路

两个点如果能相遇,那么祂们一定在同一行或同一列或同一条 \(45^{\circ}\) 倾斜的线上。用链表维护 \(6\) 个方向上相邻的点,每次把距离最近的点对领出来,如果没有被删除,就把祂们删除,标记消失前经过的时间。最后用扫描线求矩形面积并得到答案。

代码

有点长。

// Problem: P3635 [APIO2012] 苦无
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3635
// Memory Limit: 250 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL long long
const int maxn=100010;
int H,W,ti[maxn],n,p[maxn*2],cnt_p;
int dir[10][2]={
{0,2},
{3,1},
{0,1},
{3,2},
{1,2},
{0,3},
};
struct point{int x,y,id,di,nt[6],lt[6];}a[maxn];
bool ap[maxn];
bool cmp1(point a,point b){
    if((a.di==0||a.di==2)&&b.di!=0&&b.di!=2) return 1;
    if(a.di!=0&&a.di!=2&&(b.di==0||b.di==2)) return 0;
    if(a.y==b.y) return a.x<b.x;
    return a.y<b.y;
}
bool cmp2(point a,point b){
    if((a.di==1||a.di==3)&&b.di!=1&&b.di!=3) return 1;
    if(a.di!=1&&a.di!=3&&(b.di==1||b.di==3)) return 0;
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
bool cmp3(point a,point b){
    if((a.di==0||a.di==1)&&b.di!=0&&b.di!=1) return 1;
    if(a.di!=0&&a.di!=1&&(b.di==0||b.di==1)) return 0;
    if(a.y-a.x==b.y-b.x) return a.x<b.x;
    return a.y-a.x<b.y-b.x;
}
bool cmp4(point a,point b){
    if((a.di==1||a.di==2)&&b.di!=1&&b.di!=2) return 1;
    if(a.di!=1&&a.di!=2&&(b.di==1||b.di==2)) return 0;
    if(a.x+a.y==b.x+b.y) return a.x<b.x;
    return a.x+a.y<b.x+b.y;
}
bool cmp_id(point a,point b){return a.id<b.id;}
priority_queue<tuple<int,int,int>,vector<tuple<int,int,int>>,greater<tuple<int,int,int>>>q;
void del(int u){
    for(int f=0;f<6;f++){
        int lt=a[u].lt[f],nt=a[u].nt[f];
        if(lt) a[lt].nt[f]=nt;
        if(nt) a[nt].lt[f]=lt;
        if(!lt||!nt) continue;
        int dis=abs(a[nt].x-a[lt].x)+abs(a[nt].y-a[lt].y);
        if(a[lt].di==dir[f][0]&&a[nt].di==dir[f][1]) q.push({dis,lt,nt});
    }
}
class Segment_Tree{
private:
    struct node{int val,l,r,sum;}t[maxn*16];
    void push_up(int u){
        if(t[u].val) t[u].sum=p[t[u].r+1]-p[t[u].l];
        else t[u].sum=t[u<<1].sum+t[u<<1|1].sum;
    }
    void update(int u,int l,int r,int ll,int rr,int z){
        if(l>rr||r<ll) return ;
        if(ll<=l&&r<=rr){t[u].val+=z;push_up(u);return ;}
        int mid=l+r>>1;
        update(u<<1,l,mid,ll,rr,z),update(u<<1|1,mid+1,r,ll,rr,z);
        push_up(u);
    }
    void build(int u,int l,int r){
        t[u].l=l,t[u].r=r;
        if(l==r) return ;
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    }
public:
    void build(){build(1,1,cnt_p);}
    void update(int l,int r,int z){update(1,1,cnt_p,l,r,z);}
    int query(){return t[1].sum;}
}Tr;
struct Line{
    int x,be,en,z;
    bool operator<(const Line t)const{return x<t.x;}
}b[maxn*2];
signed main(){
    read(H,W,n);
    for(int i=1;i<=n;i++){
        read(a[i].x,a[i].y,a[i].di);
        ap[i]=1;
        a[i].id=i;
        if(a[i].di==1) ti[i]=a[i].y*2-2;
        if(a[i].di==3) ti[i]=(H-a[i].y)*2;
        if(a[i].di==0) ti[i]=(W-a[i].x)*2;
        if(a[i].di==2) ti[i]=a[i].x*2-2;
    }
    sort(a+1,a+1+n,cmp1);
    for(int i=1;i<n;i++){
        if(a[i+1].di==1||a[i+1].di==3) break;
        if(a[i].y!=a[i+1].y) continue;
        a[i].nt[0]=a[i+1].id,a[i+1].lt[0]=a[i].id;
    }
    sort(a+1,a+1+n,cmp2);
    for(int i=1;i<n;i++){
        if(a[i+1].di==0||a[i+1].di==2) break;
        if(a[i].x!=a[i+1].x) continue;
        a[i].nt[1]=a[i+1].id,a[i+1].lt[1]=a[i].id;
    }
    sort(a+1,a+1+n,cmp3);
    for(int i=1,nw=2;i<n;i++){
        if((a[i].di==0||a[i].di==1)&&a[i+1].di!=0&&a[i+1].di!=1){nw=3;continue;}
        if(a[i].y-a[i].x!=a[i+1].y-a[i+1].x) continue;
        a[i].nt[nw]=a[i+1].id,a[i+1].lt[nw]=a[i].id;
    }
    sort(a+1,a+1+n,cmp4);
    for(int i=1,nw=4;i<n;i++){
        if((a[i].di==1||a[i].di==2)&&a[i+1].di!=1&&a[i+1].di!=2){nw=5;continue;}
        if(a[i].x+a[i].y!=a[i+1].x+a[i+1].y) continue;
        a[i].nt[nw]=a[i+1].id,a[i+1].lt[nw]=a[i].id;
    }
    sort(a+1,a+1+n,cmp_id);
    for(int i=1;i<=n;i++){
        for(int f=0;f<6;f++){
            if(!a[i].nt[f]) continue;
            int j=a[i].nt[f];
            if(a[i].di!=dir[f][0]||a[j].di!=dir[f][1]) continue;
            int dis=abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y);
            q.push({dis,i,j});
        }
    }
    while(!q.empty()){
        int nw_ti=get<0>(q.top());
        while(!q.empty()){
            auto[t,u,v]=q.top();
            if(t!=nw_ti) break;
            q.pop();
            if(!ap[u]&&ti[u]!=t||!ap[v]&&ti[v]!=t) continue;
            if(ap[u]) del(u);
            if(ap[v]) del(v);
            ap[u]=ap[v]=0;
            ti[u]=ti[v]=t;
        }
    }
    for(int i=1;i<=n;i++){
        int x=a[i].x,y=a[i].y,xx,yy;
        int dis=ti[i]/2;
        if(a[i].di==0) xx=x+dis,yy=y;
        if(a[i].di==1) xx=x,yy=y-dis;
        if(a[i].di==2) xx=x-dis,yy=y;
        if(a[i].di==3) xx=x,yy=y+dis;
        if(x>xx) swap(x,xx);
        if(y>yy) swap(y,yy);
        xx++,yy++;
        cnt_p++;
        b[cnt_p]={x,y,yy,1};
        p[cnt_p]=y;
        cnt_p++;
        b[cnt_p]={xx,y,yy,-1};
        p[cnt_p]=yy;
    }
    sort(p+1,p+1+cnt_p);
    cnt_p=unique(p+1,p+1+cnt_p)-p-1;
    sort(b+1,b+1+n*2);
    LL ans=0;
    auto get_id=[](int x){return lower_bound(p+1,p+1+cnt_p,x)-p;};
    Tr.build();
    for(int i=1;i<n*2;i++){
        Tr.update(get_id(b[i].be),get_id(b[i].en)-1,b[i].z);
        ans+=1ll*Tr.query()*(b[i+1].x-b[i].x);
    }
    write(ans);
    return 0;
}
posted @ 2026-05-27 22:28  Link-Cut_Trees  阅读(11)  评论(0)    收藏  举报