1. 程式人生 > >【AtCoder】【思維】【圖論】Splatter Painting(AGC012)

【AtCoder】【思維】【圖論】Splatter Painting(AGC012)

amp code 暴力 oid 沒有 null 如何 class algo

題意:

有一個含有n個點的無向圖,所有的點最初顏色均為0。有q次操作,每次操作將v[i]周圍的距離小於等於d[i]的點全部都染成顏色c[i]。最後輸出每個點的最終的顏色。

數據範圍:

1<=n,m,q<=10^5
0<=d[i]<=10
1<=c[i]<=10^5

思路:

看見1<=d[i]<=10,這個條件,第一反應當然是暴力啦。但是如果從一個點總是能夠訪問所有的節點,那麽這就變成O(n^2)了。那麽我們應當考慮時間復雜度更加穩定的算法。
然後開始考慮如何優化。倒著掃操作是很容易想到的。然後可以對於每一個點維護一個對於當前已經掃完的操作的最大值。假如說當前在點v,然後當前的d為d[i],假如說d[i]<=maxd[v],那麽就說明在後面的操作中將當前這一次操作所產生的效果抵消了。於是就可以直接返回了。
經過上述的優化之後,我們發現能夠進入一個點並成功進行拓展的條件是d[i]>maxd[v],那麽因為1<=d[i]<=10,所以說就算d[i]從1~10依次排列,也只會對於v點訪問最多10次。這樣子時間復雜度就變為了穩定的O(10*n+m),從而穩當了不少。

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100000
using namespace std;
struct node
{
    int to;
    node *nxt;
}edges[MAXN*2+5];
node *ncnt=&edges[0],*Adj[MAXN+5];
int n,m,q,col[MAXN+5],maxd[MAXN+5];
int V[MAXN+5],D[MAXN+5],C[MAXN+5];
void Init()
{
    memset(maxd,-1,sizeof(maxd));
}
void AddEdge(int u,int v)
{
    node *p=++ncnt;
    p->to=v;
    p->nxt=Adj[u];
    Adj[u]=p;
    
    node *q=++ncnt;
    q->to=u;
    q->nxt=Adj[v];
    Adj[v]=q;
}
void DFS(int u,int d,int c)
{
    if(col[u]==0)//沒有賦過值才賦值
        col[u]=c;
    if(maxd[u]>=d)//判斷當前操作是否被後面的操作覆蓋了
        return;
    if(d==0)//到達能夠賦值的邊界了
        return;
    maxd[u]=d;
    for(node *p=Adj[u];p!=NULL;p=p->nxt)
    {
        int v=p->to;
        DFS(v,d-1,c);//d--,繼續賦值
    }
}
int main()
{
    Init();
    scanf("%d %d",&n,&m);
    int u,v;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&u,&v);
        AddEdge(u,v);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
        scanf("%d %d %d",&V[i],&D[i],&C[i]);
    for(int i=q;i>=1;i--)//倒著處理
        DFS(V[i],D[i],C[i]);
    for(int i=1;i<=n;i++)
        printf("%d\n",col[i]);
    return 0;
}

【AtCoder】【思維】【圖論】Splatter Painting(AGC012)