这次比赛啥都不说了===心酸。
这次小白赛难度其实不高,除了A之外我应该都能做出来才对===心酸
FG很简单,不写题解了。A放弃了--
H 好朋友——并查集+离散化
先把所有朋友关系合并到并查集里面;然后枚举敌人关系,只要两者在一个朋友集合里面就是矛盾的。
当时只用了并查集没过,想着10^9数值的话tree数组直接用map,但是map本身内部有排序,处理速度不如数组,导致时间超时
这道题数据设计的比较强。。。只能离散化,离散化就是把一组数去重排序之后映射成下标,即
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e6 + 5;
const int N = 1e9+1;
int parent[MAXN];
//map<int,int> parent;
int find(int i) {
if (parent[i] != i) parent[i] = find(parent[i]);
return parent[i];
}
void uni(int x, int y)
{
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty)
{
parent[rooty] = rootx;
}
}
int a[MAXN],b[MAXN],c[MAXN];
vector<int> d;
signed main()
{
int t;cin>>t;
while(t--){
d.clear();
int n;cin>>n;
for(int i=1;i<=n*2;++i) parent[i]=i;
for(int i=0;i<n;++i){
scanf("%d %d %d",&a[i],&b[i],&c[i]);
d.push_back(a[i]);
d.push_back(b[i]);
}
sort(d.begin(), d.end());
d.erase(unique(d.begin(),d.end()),d.end());
for (int i = 0; i < n; ++i) {
a[i] = lower_bound(d.begin(), d.end(), a[i]) - d.begin() + 1,
b[i] = lower_bound(d.begin(), d.end(), b[i]) - d.begin() + 1;
}
bool flag=false;
for(int i=0;i<n;++i){
if(c[i]==1){
uni(a[i],b[i]);
}
}
for(int i=0;i<n;++i){
if(c[i]==0){
int rootx = find(a[i]);
int rooty = find(b[i]);
if (rootx == rooty) {
cout<<"NO"<<endl;
flag=true;
break;
}
}
}
if(!flag) cout<<"YES"<<endl;
}
return 0;
}I 求和--dfs重新编号
已知有 n个节点,有 n−1 条边,形成一个树的结构。
给定一个根节点 k,每个节点都有一个权值,节点i的权值为 vi。
给 m个操作,操作有两种类型:
1 a x :表示将节点 a的权值加上 xxx
2 a :表示求 a 节点的子树上所有节点的和(包括 a 节点本身)
本来想直接暴力,每次查询直接dfs求距离---超时
void dfs(int u,int father){
sum[u]=num[u];
for(int i=h[u];i;i=ne[i])if(p[i]!=father){
dfs(p[i],u);
sum[u]+=sum[p[i]];
}
} 想了想,这种动态单点修改求区间和难道不是树状数组和线段树吗?
但是树状数组要从1开始并且连续区间和阿。——自然也就想到利用dfs对整棵树重新编号,编号后,可以使得任意一颗子树的序号连续
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e6 + 5;
#define N 1000005
int tree[MAXN]={0};
int MAXNTREE;
inline long long query(int pos)
{
long long ans = 0;
while (pos > 0) {
ans+=tree[pos];
pos -= pos & (-pos);
}
return ans;
}
inline void update(int pos, int val)
{
int ans = 0;
while (pos <= MAXNTREE) {
tree[pos]+=val;
pos += pos & (-pos);
}
}
ll tot,dis[N],fa[N],h[N],ne[N<<1],p[N<<1],wi[N<<1];
void addEdge(int u,int v,int w){p[++tot]=v;ne[tot]=h[u];h[u]=tot;wi[tot]=w;}
void add(int u,int v){p[++tot]=v;ne[tot]=h[u];h[u]=tot;}
void addOrEdge(int u,int v){ne[++tot]=h[u];h[v]=tot;}
ll num[MAXN];ll siz[MAXN]={0};
ll no[MAXN];//重新编号使得子树的节点号连续
int g_cnt=0;
void dfs(int u,int father){
no[u]=++g_cnt;
siz[u]=1;
for(int i=h[u];i;i=ne[i])if(p[i]!=father){
dfs(p[i],u);
siz[u]+=siz[p[i]];
}
}
signed main()
{
int n,m,rt;cin>>n>>m>>rt;
tot=0;
MAXNTREE=n;
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);add(v,u);
}
dfs(rt,0);
for (int i = 1; i <= n; ++i) update(no[i], num[i]);
for(int i=1;i<=m;++i){
int x,u,w; scanf("%d",&x);
if(x==1){
scanf("%d %d",&u,&w);
update(no[u],w);
}else{
scanf("%d",&u);
printf("%lld\n", query(no[u] + siz[u] - 1) - query(no[u] - 1));
}
}
return 0;
} J 求和——前缀和
这个是真的秀。。。我太菜了 只想到了没想到
可以用前缀和来算
#include <bits/stdc++.h>
#define ll long long
const int MAXN = 500005;
using namespace std;
ll a[MAXN], sum[MAXN];
const int MOD = 1e9 + 7;
int main()
{
int n;
scanf("%d", &n);
assert(1 <= n && n <= 500000);
ll ans = 0;
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
sum[i] = (sum[i - 1] + a[i]) % MOD;
ans = (ans + a[i] * a[i]) % MOD;
}
ans = (n - 1LL) * ans % MOD;
for (int i = 1; i <= n; i++)
ans = (ans - 2LL * a[i] * sum[i - 1] % MOD + MOD) % MOD;
printf("%lld\n", ans);
} B 组队——二分
比较简单。先排序,每个数num[i]二分找到第一个大于等于num[i]+k的数位置,两者下标相减就是能取到的数。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
const int MAXN = 5e5 + 10;
int num[MAXN];
map<int,int> has;
signed main()
{
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=0;i<n;++i){
cin>>num[i];
}
sort(num,num+n);
int l=1,r=n;
int ans=0;
for(int i=0;i<n;++i){
int x = lower_bound(num+i+1,num+n,num[i]+k)-num;
//cout<<x<<endl;
if(num[x]==num[i]+k){
ans=max(ans,x-i+1);
}else{
ans=max(ans,x-i);
}
}
cout<<ans<<endl;
}
return 0;
} 
京公网安备 11010502036488号