先预处理出所有与 x x x轴平行的边,然后暴力判断其中两条边能不能构成矩形。
#include
using namespace std;
#define LL long long
const LL MAXN = 2005;
LL n;
struct node1 {
LL x, y;
bool operator<(const node1 &t) const { return x < t.x || (x == t.x && y < t.y); }
} a[MAXN];
struct node2 {
LL xa, xb;
LL ya, yb;
LL len;
bool operator<(const node2 &t) const {
return len < t.len || (len == t.len && xa < t.xa) || (len == t.len && xa == t.xa && ya < t.ya);
}
};
vector<node2> b;
int main() {
scanf("%lld", &n);
for (LL i = 1; i <= n; i++) {
scanf("%lld%lld", &a[i].x, &a[i].y);
}
sort(a + 1, a + n + 1);
for (LL i = 1; i <= n; i++) {
for (LL j = i + 1; j <= n; j++) {
if (a[i].y == a[j].y) {
node2 temp;
temp.len = a[j].x - a[i].x;
temp.xa = a[i].x;
temp.ya = a[i].y;
temp.xb = a[j].x;
temp.yb = a[j].y;
b.push_back(temp);
}
}
}
sort(b.begin(), b.end());
LL ans = 0;
for (LL i = 0; i < b.size(); i++) {
for (LL j = i + 1; j < b.size(); j++) {
if (b[j].len != b[i].len)
break;
if (b[j].xa == b[i].xa)
ans++;
}
}
printf("%lld", ans);
}
把删边改为加边,问题转化为求加任意数量的边,使得最终图为连通图,最少能得到多少钱?
显然,最少的边数为 n − 1 n-1 n−1,又要是连通图,就是最小生成树。
所以先标记选择的最小生成树上的边,然后在剩下的边里选择,得到最大的钱数。
#include
using namespace std;
#define LL long long
const LL MAXN=200005;
struct node{
LL u,v,w;
bool operator <(const node &t)const{
return w<t.w;
}
}a[MAXN];
LL n,m;
LL f[MAXN];
bool vis[MAXN];
LL fi(LL x){
if(f[x]==x)return x;
return f[x]=fi(f[x]);
}
int main(){
scanf("%lld%lld",&n,&m);
for(LL i=1;i<=m;i++){
scanf("%lld%lld%lld",&a[i].u,&a[i].v,&a[i].w);
}
sort(a+1,a+m+1);
for(LL i=1;i<=n;i++){
f[i]=i;
}
LL cnt=0;
for(LL i=1;i<=m;i++){
LL fx=fi(a[i].u),fy=fi(a[i].v);
if(fx!=fy){
f[fx]=f[fy];
vis[i]=true;
cnt++;
}
if(cnt==n-1)break;
}
LL ans=0;
for(LL i=1;i<=m;i++){
if(!vis[i]){
ans=max(ans,ans+a[i].w);
}
}
printf("%lld",ans);
}
首先想到的是暴力去做,但是这样的时间复杂度错了,因为边数最大的情况为 n 2 n^2 n2左右,所以一次 B F S BFS BFS为 O ( n + m ) = O ( n 2 ) O(n+m)=O(n^2) O(n+m)=O(n2),这样一来时间复杂度就来到了 O ( n 4 ) O(n^4) O(n4)。
所以我们需要进行一点小优化,第一次 B F S BFS BFS时可以对未删边时的最短路上的边进行标记,如果没有删掉这些边,那答案是与第一次 B F S BFS BFS一样的。这样就可以通过了。
#include
using namespace std;
#define LL long long
const LL MAXN=405;
const LL inf=10000000000;
LL n,m;
LL u[MAXN*MAXN],v[MAXN*MAXN];
vector<pair<LL,LL> >a[MAXN];
LL dis[MAXN];
queue<LL>q;
bool is[MAXN*MAXN];
pair<LL,LL> pre[MAXN*MAXN];
LL bfs(LL del){
while(!q.empty())q.pop();
q.push(1);
for(LL i=1;i<=n;i++){
dis[i]=inf;
}
dis[1]=0;
while(!q.empty()){
LL t=q.front();q.pop();
for(LL i=0;i<a[t].size();i++){
LL xx=a[t][i].first;
LL yy=a[t][i].second;
if(del==yy)continue;
if(dis[xx]>dis[t]+1){
dis[xx]=dis[t]+1;
q.push(xx);
if(del==0)pre[xx]={t,yy};
}
}
}
if(dis[n]>=inf)dis[n]=-1;
return dis[n];
}
int main(){
// freopen("C.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(LL i=1;i<=m;i++){
scanf("%lld%lld",&u[i],&v[i]);
a[u[i]].push_back({v[i],i});
}
LL ans=bfs(0),now=n;
while(now>1){//因为无解时now会变为0,所以不能写成now!=1
is[pre[now].second]=true;
now=pre[now].first;
}
for(LL i=1;i<=m;i++){
if(is[i])printf("%lld\n",bfs(i));
else printf("%lld\n",ans);
}
}
这是一道假的博弈论题目,分析一波发现小 A A A一定会选择子树中最大的那一个,小 B B B则会选择最小的。
所以可以 d f s dfs dfs遍历一遍树,维护当前路径上的中位数,这个离散化一下,用树状数组维护,二分查找中位数就行。
#include
using namespace std;
#define LL long long
const LL MAXN=100005;
LL n,m;
LL a[MAXN];
vector<LL>b[MAXN];
LL c[MAXN],f[MAXN];
LL s[MAXN],dep[MAXN];
LL d[MAXN];
LL lowbit(LL x){
return x&(-x);
}
LL query(LL x){
LL res=0;
while(x){
res+=s[x];
x-=lowbit(x);
}
return res;
}
void add(LL x,LL k){
while(x<=100000){
s[x]+=k;
x+=lowbit(x);
}
}
void dfs(LL x,LL fa){
dep[x]=dep[fa]+1;
if(dep[x]&1)f[x]=0;
else f[x]=1e9;
bool flg=false;
add(a[x],1);
for(LL i=0;i<b[x].size();i++){
LL xx=b[x][i];
if(xx==fa)continue;
flg=true;
dfs(xx,x);
if(dep[x]&1)f[x]=max(f[x],f[xx]);
else f[x]=min(f[x],f[xx]);
}
if(!flg){
LL l=1,r=m;
while(l<r){
LL mid=(l+r)>>1;
if(query(mid)>=(dep[x]+1)/2)r=mid;
else l=mid+1;
}
if(dep[x]&1)f[x]=c[r];
else{
if(query(r)>dep[x]/2)f[x]=c[r];
else{
LL temp=r;
l=r+1;r=m;
while(l<r){
LL mid=(l+r)>>1;
if(query(mid)-query(temp))r=mid;
else l=mid+1;
}
f[x]=(c[r]+c[temp])/2;
}
}
}
add(a[x],-1);
}
int main(){
scanf("%lld",&n);
for(LL i=1;i<=n;i++){
scanf("%lld",&a[i]);
c[i]=a[i];
d[i]=a[i];
}
sort(c+1,c+n+1);
m=unique(c+1,c+n+1)-c-1;
for(LL i=1;i<=n;i++){
a[i]=lower_bound(c+1,c+m+1,a[i])-c;
}
for(LL i=1;i<n;i++){
LL u,v;
scanf("%lld%lld",&u,&v);
b[u].push_back(v);
b[v].push_back(u);
}
dfs(1,0);
printf("%lld",f[1]);
}