虛樹的主要思想:
所以怎麼辦:
q.clear();
int m;
scanf("%d",&m);
for(int i=1;i<=m;++i)
sort(q.begin(),q.end(),cmp);
for(int i=0;iq是乙個vector,我們開始先對所有節點按尤拉序(即深度優先搜尋是訪問的順序)排序,然後對每兩個相鄰的節點將lca放入q中(可知這樣一定會將所有有效節點放入q中)。然後一波去重,再按尤拉序排序即可。
如果你還不會lca的話請到這裡
然後我們得到了乙個遍歷表,向深度優先搜尋一樣搜一遍即可。
這裡要注意每個節點x只有當他下乙個節點y是他的子節點時(即\(dfn[x]+size[x]>=dfn[y]\)時,其中\(dfn\)為尤拉序,\(size\)為子樹大小)才訪問下乙個節點,並用下乙個點的資訊更新當前節點。
對於兩點間的最短樹邊,我們可以用倍增來尋找(當然也可以用st表\(o(1)\)求,但這題並不要求)。
long long getmin(int x,int lca)
}return ret;
}
對於每個節點,如果他一定要被割掉,則當前點的最小花費為當前點到父親節點的最小樹邊,否則為所有子節點的最小花費和和當前點到父親節點的最小樹邊的最小值。
void dfs1()
else dp[y]=1e18,dfs1(),dp[y]=min(dp[y],getmin(y,x));
ret+=dp[y];
}else break;
} if(ret)dp[x]=min(dp[x],ret);
}
**中的it為當前訪問到的節點在q中的編號
然後就可以寫出**了,需要注意一些初始化的細節:
#includeusing namespace std;
const int n=600010,t=20;
int n;
int tot,bian[n<<1],nxt[n<<1],zhi[n<<1],head[n];
void add(int x,int y,int z)
int dfn[n],cnt;
int fa[n][t],c[n][t],dep[n],sz[n];
vectorq;
bool cmp(int x,int y)
} if(x==y)return x;
for(int i=t-1;~i;--i)
} return fa[x][0];
}long long getmin(int x,int lca)
} return ret;
}#define it vector::iterator
long long dp[n];
int it,v[n];
void dfs1()
else dp[y]=1e18,dfs1(),dp[y]=min(dp[y],getmin(y,x));
ret+=dp[y];
}else break;
} if(ret)dp[x]=min(dp[x],ret);
}int main()
sort(q.begin(),q.end(),cmp);
for(int i=0;iq.push_back(1);
sort(q.begin(),q.end());
q.erase(unique(q.begin(),q.end()),q.end());
sort(q.begin(),q.end(),cmp);
m=q.size();it=0;
dp[q[0]]=1e18;
dfs1();
for(int i=0;iprintf("%lld\n",dp[*q.begin()]);
}}
SDOI2011 消耗戰 虛樹
有m次詢問,又有詢問的總的點數之和是小於等於5e5的,所以,其實就是乙個虛樹的模板了,直接用棧維護乙個虛樹即可。期間寫的時候出現了一點問題 初始化的時候,不只是要初始那些輸入的k個結點,還有k個結點的lca的衍生結點也是需要初始化的,所以初始化不到位會mle和tle的,這裡不要忘。include i...
SDOI2011 消耗戰 (虛樹)
題意 給一棵n個頂點的樹,每條樹邊有邊權。m次詢問,每次詢問給出k個點,問使得這k個點均不與1號點 根節點 相連的最小代價 解法 虛樹用法 在單次詢問只涉及樹中少量節點時,可以建立一顆只包含關鍵節點的樹 將無用節點組成的鏈簡化為邊或者刪掉,形成虛樹,最後在虛樹上進行dp 關鍵點為詢問點和lca 虛數...
虛樹 sdoi2011《消耗戰》
卡著時間過得,大概是因為全用了ll,時間漲了一倍吧?懶得改了,第一道虛樹還是思路比較重要 下面這段文字是複製來的 給出一棵樹.每次詢問選擇一些點,求一些東西.這些東西的特點是,許多未選擇的點可以通過某種方式剔除而不影響最終結果.於是就有了建虛樹這個技巧.我們可以用log級別的時間求出點對間的lca....