C、D
C:
把所有0的边所连的两个点加入同一个集合,如果对于某类型所有点都在同一个集合就是correct。
然后就是500^3的floyd
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 1000000007;
/*-----------code------------*/
class DisjointSet{ //简版
public:
int parent[N];
void init(int n)
{
for(int i=0;i<=n;i++)
parent[i]=i;
}
int find(int x)
{
return x==parent[x]? x: (parent[x]=find(parent[x]));
}
void merge(int x,int y)
{
int rtx=find(x);
int rty=find(y);
if(rtx==rty) return ;
parent[rtx]=rty;
}
}ds;
int dp[512][512];
int pos[N],a[N];
int main(){
int n,m,k,c,p=1;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++){
scanf("%d",&a[i]);
for(int j=0;j<a[i];j++) pos[p++]=i;
}
CLR(dp,0x3f);
for(int i=1;i<=k;i++) dp[i][i]=0;
ds.init(n);
while(m--){
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
if(c==0) ds.merge(x,y);
if(dp[pos[x]][pos[y]]>c){
dp[pos[x]][pos[y]]=c;
dp[pos[y]][pos[x]]=c;
}
}
p=1;
for(int i=1;i<=k;i++){
for(int j=0;j<a[i];j++){
if(ds.find(p)!=ds.find(p+j)){
puts("No");
return 0;
}
}
p+=a[i];
}
puts("Yes");
for(int t=1;t<=k;t++){
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
dp[i][j]=min(dp[i][j],dp[i][t]+dp[t][j]);
}
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++) printf("%d ",(dp[i][j]>=dp[0][0])?-1:dp[i][j]);
puts("");
}
return 0;
}
D:
二进制每一位拆开分析,这样就是01的数组,对于连续x个1,合并一次后就变为x-1个。总共有多少个1,就有多少个2^i(i是第几位)。
然后每次更新的话,用L[i]记录以i为结尾,从左边起最多的连续1,R[i]表示以i为开头至右最多连续1。
如果是0更新成1,那么和的变化是 cal(L[pos-1]+R[pos+1]+1)-(cal(L[pos-1])+cal(R[pos+1])),cal函数是计算连续1长度为x,一共能变成多少个1。然后还需要更新区间[ pos-L[pos-1] , pos+R[pos+1] ]内的R[i]和L[i]的值,用树状数组维护区间更新。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 1000000007;
/*-----------code------------*/
class BIT{
public:
typedef int type;
type sum[N];
int n;
void init(int n){
this->n=n;
fill(sum,sum+n+1,0);
}
void add(int i,type x){
for(;i>=1;i-= -i&i) sum[i]+=x;
}
void update(int l,int r,int x){
add(l-1,-x);
add(r,x);
}
void set(int i,int x){
update(i,i,x);
}
type get(int i){
type ans=0;
if(i) for(;i<=n;i+= -i&i) ans+=sum[i];
return ans;
}
type operator[](const int i){
return get(i);
}
}l[20],r[20];
int cnt[20][N];
ll sum;
ll cal(ll x,int i){
return (x+1)*x/2*(1<<i);
}
ll solve(int i,int c,int id){
if(cnt[id][i]==c) return 0;
cnt[id][i]=c;
ll ans=0;
BIT &L=l[id], &R=r[id];
if(c){
ans-=cal(L[i-1],id)+cal(R[i+1],id);
ans+=cal(L[i-1]+R[i+1]+1,id);
L.update(i,i+R[i+1],1+L[i-1]);
R.update(i-L[i-1],i,1+R[i+1]);
}else{
ans-=cal(L[i-1]+R[i+1]+1,id);
ans+=cal(L[i-1],id)+cal(R[i+1],id);
L.update(i,i+R[i+1],-L[i]);
R.update(i-L[i-1],i,-R[i]);
}
return ans;
}
int main(){
int n,m,a;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a);
for(int j=0;j<20;j++) if(1<<j&a){
cnt[j][i]=1;
}
}
for(int i=0;i<20;i++){
l[i].init(n);
r[i].init(n);
ll x=0;
for(int j=1;j<=n;j++){
if(cnt[i][j]==1) x++, l[i].set(j,x);
else{
sum+=cal(x,i);
//printf("add len:%d 2^%d\n",x,i);
x=0;
}
}
sum+=cal(x,i);
//printf("add len:%d 2^%d\n",x,i);
x=0;
for(int j=n;j>=1;j--){
if(cnt[i][j]==1) x++, r[i].set(j,x);
else{
x=0;
}
}
}
while(m--){
int pos,val;
scanf("%d%d",&pos,&val);
for(int i=0;i<20;i++)
sum+=solve(pos,val>>i&1,i);
printf("%I64d\n",sum);
}
return 0;
}