树状数组-并查集

1.树状数组

给你一个序列a[1]~a[N],你需要找出每一个数a[i],在区间[1, i - 1]有多少个数小于等于a[i]。

int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int y)
{
    while(x<=n)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
    //return;//重点
}
int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}

给你一个初始全为0的序列a[1]~a[N],有q次操作,每次操作有两种类型,第一种操作时区间翻转操作,将区间[l, r]进行翻转,也就是原来为0的数现在变为1,原来为1的数现在变为0.第二组是查询操作,查询位置loc的值是0还是1.

int lowbit(int x)
{
    return x&(-x);
}
void update(int l,int r)
{
    while(l>0)
    {
        w[l]+=1;
        l-=lowbit(l);
    }
    while(r>0)
    {
        w[r]+=1;
        r-=lowbit(r);
    }
}
int sum(int x)
{
    int sum=0;
    while(x<=N)
    {
        sum+=w[x];
        x+=lowbit(x);
    }
    return sum;
}

2.并查集

把这些柱子当成N个节点,编号为1~N,然后给你若干条边,每条边连接两个点,且每条边有一个权值。现在让你删去其中的若干条边,使得这N个节点相互连通。当然有很多种不同的删法,现在让你找出一种删法,使得删除的边的权值和最大,如果不存在删法,使得这N个节点相联通,输出-1,否则,输出删除的最大边权和。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct edge
{
    int u, v;
    int w;
    friend bool operator < (edge a, edge e)
    {
        return a.w<e.w;
    }
}e[1000000];
vector<edge> part;
vector<long> father(1000000, -1);
long findfather(long i)
{
    if (father[i] == -1) return i;
    else  return father[i] = findfather(father[i]);
}
void merge_union(long x, long y)
{
    long f1 = findfather(x);
    long f2 = findfather(y);
    father[f1] = f2;
}
long findmin(long n)
{
    sort(part.begin(), part.end());
    vector<edge> mst;
    long sum = 0;
    long x = 0;
    for (long i = 0; i<part.size(); i++)
    {
        if (findfather(part[i].u) == findfather(part[i].v)) continue;
        else
        {
            merge_union(part[i].u, part[i].v);
            sum += part[i].w;
            mst.push_back(part[i]);
        }
    }
    if (mst.size() != n - 1)  return -1;
    return sum;
}
int main()
{
    long N,M;
    long T;
    cin >> T;
    while (T--)
    {
        cin >> N >> M;
        long x,sum=0;
        for (long i = 0; i<M; i++)
        {
            edge ed;
            cin >> ed.u >> ed.v >> ed.w;
            part.push_back(ed);
            sum += ed.w;
        }
        x = findmin(N);
        if (x == -1) cout <<  x << endl;
        else
            cout << sum-x << endl;
        part.clear();
        father.clear();
        father.resize(1000000, -1);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值