給出一張n個點m條邊的無向圖,點的顏色為0/1,每次有兩種操作:
1.asksum x y,查詢兩點顏色為x和y的邊的權值之和
2.change x,將x顏色取反
最直接的做法是每次改變點的顏色豆漿與該點所連的邊更新,\(o(q*m)\),超時
那麼我們考慮將點根據度數分類,將度數\(的點稱為普通點,否則為超級點。設定sum[i][0/1]代表第i個點(超級點)與顏色為0/1相連的邊的權值和。普通點顏色改變,暴力修改與普通點相連的所有的點對答案的貢獻\(o(\sqrt)\);超級點顏色改變,直接修改對答案的貢獻\(o(1)\);最後修改與變顏色的點相連的所有超級點的sum,具體細節見**
1.用vector寫會wa,不知道為什麼
2.一些寫的更詳細的blog,對於答案的貢獻修改有清晰的介紹
hdu4467 graph(構造法求解)
hdu4467 graph(圖的分塊)
//vector(wa)
#include #include #include #include using namespace std;
#define f(i,a,b) for(int i=a;i<=b;++i)
#define r(i,a,b) for(int i=a;ive[n];
void change(int x)
else
sort(e+1,e+1+m);
int cnt=0;
for(int i=1,j;i<=m;i=j)
f(i,1,cnt) du[e[i].u]++,du[e[i].v]++;
int judge=sqrt(cnt);
f(i,1,n) super[i]=(du[i]>=judge);
f(i,1,cnt)
else ve[e[i].u].push_back(node(e[i].v,e[i].w));
if(super[e[i].v]) else ve[e[i].v].push_back(node(e[i].u,e[i].w));
ans[color[e[i].u]+color[e[i].v]]+=e[i].w;
}printf("case %d:\n", ++cas);
for(scanf("%d",&q);q--;)
else
}// check();
}return 0;
}
//鄰接表(ac)
#include #include #include #include #include using namespace std;
#define f(i,a,b) for(int i=a;i<=b;++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int n = 100100;
int n,m,q,cas;
int color[n],du[n],super[n];
ll sum[n][2],ans[3];
struct edge
bool operator<(const edge &p)const
sort(e+1,e+m+1);
//對邊去重
int cnt=0;
for(int i=1,j;i<=m;i=j)
f(i,1,cnt) du[e[i].u]++,du[e[i].v]++;//計算度數
int judge=sqrt(cnt);//設定界限,高於界限為超級點,否則為普通點
f(i,1,n) super[i]=(du[i]>=judge);
mem(head,0);tot=0;mem(ans,0);mem(sum,0);
f(i,1,cnt)//構建鄰接表
else add(0,x,y,z);
if(super[y]) else add(0,y,x,z);
ans[color[x]+color[y]]+=z;//將邊權記錄到答案中
}printf("case %d:\n", ++cas);
for(scanf("%d",&q);q--;)
else
}else
}for(int i=head[x][1];i;i=nxt[i])//暴力修改與點相連的超級點sum}}
}return 0;
}
HDU 4467 Graph(莫隊思想)
題意 給你n個點,m條邊,每條邊有乙個權值,有兩個操作,乙個是修改單點的顏色 顏色只有0,1兩種 乙個是詢問邊的兩個端點都為指定顏色的權值和。思路 由於每個點的顏色只有0,1兩種,那麼答案只有3種情況 00,01,11 用乙個陣列維護即可。即ans 0 統計邊的兩端都是0的權值和,ans 1 統計邊...
hdu 4467 Graph 莫隊演算法思想
題目連線 hdu 4467 graph 題意 給你n個點,m條邊,每條邊有乙個權值,有兩個操作,乙個是修改單點的顏色,乙個是詢問邊的兩個端點都為指定顏色的權值和 題解 這題如果暴力的話,就是維護3個ans,乙個是兩個端點都為0的,乙個是乙個為1乙個為0的,最後還有個兩個端點都為1的,對於每個詢問,可...
hdu4612 縮點 樹的直徑
題目大意 求乙個連通圖然後加一條邊使得橋的數目最少 題解思路 先把橋兩邊不是的點所有連通的點都縮成乙個點 然後把縮完的點構成一顆樹那麼再直徑的兩端加一條邊就是最優方案 注意 判斷重邊 題目鏈結 include include include include include include inclu...